Compare commits

..

17 Commits
gui ... main

3
.gitignore vendored

@ -0,0 +1,3 @@
out/
__pycache__/
nft/

@ -1,49 +0,0 @@
#!/usr/bin/env python3
from tkinter import *
from tkinter import ttk
def init_gui(root):
def btn_apply_clicked():
try:
width = int(input_width.get())
height = int(input_height.get())
print(f'apply clicked, resolution: {width}x{height}')
except:
print('Please enter a valid resolution')
root.title('Generative Art')
algos = ['waves', 'hyphae']
frame_top = ttk.Frame(root, padding=10)
frame_top.pack(side=TOP)
#frame_top.grid()
#ttk.Label(frame_top, text="Hello World!").grid(column=0, row=0)
Combo = ttk.Combobox(frame_top, values = algos)
Combo.set('Pick an algorithm')
Combo.grid(column=0, row=0)
input_width = ttk.Entry(frame_top, width=6)
input_width.insert(0, 'Width')
input_width.grid(column=1, row=0)
input_height = ttk.Entry(frame_top, width=6)
input_height.insert(0, 'Height')
input_height.grid(column=2, row=0)
ttk.Button(frame_top, text="Apply", command=btn_apply_clicked).grid(column=3, row=0)
ttk.Button(frame_top, text="Quit", command=root.destroy).grid(column=4, row=0)
frame_left = ttk.Frame(root)
frame_left.pack(side=LEFT)
frame_right = ttk.Frame(root)
frame_right.pack(side=RIGHT)
def main():
root = Tk()
init_gui(root)
root.mainloop()
if __name__ == '__main__':
main()

@ -6,7 +6,7 @@ import random
from utils import circle_fill
from utils import random_color
WIDTH, HEIGHT = 1000, 1000
WIDTH, HEIGHT = 500, 500
ANGLE_RANDOM_MIN = -0.6
ANGLE_RANDOM_MAX = 0.6
# how much to shrink each consecutive circle
@ -87,7 +87,6 @@ def grow_subs(ctx, subs, branches):
for branch in subs:
# create a sub branch based on length
sub_branches = len(branch.nodes) // 7 * 2
print(f'creating {sub_branches} subs')
if sub_branches > 1:
created = True
@ -143,8 +142,6 @@ def main():
return
ctx.set_source_rgb(0.0, 0.0, 0.1*x)
subs = grow_subs(ctx, subs, branches)
surface.write_to_png("out/hyphae.png") # Output to PNG
input('next')
finally:
surface.write_to_png("out/hyphae.png") # Output to PNG

@ -0,0 +1,217 @@
#!/usr/bin/env python3
import cairo
import math
import random
import threading
import time
import socket
import colorsys
from utils import circle_fill
from utils import circle_clip_fill
from utils import random_color
import numpy
WIDTH, HEIGHT = 1024, 1024
ANGLE_RANDOM_MIN = -0.6
ANGLE_RANDOM_MAX = 0.6
# how much to shrink each consecutive circle
SHRINK = 0.00004
start_r = 0.01
NODE_ARRAY = None
start_hue = 0
# should be ~ 1 px
MIN_RADIUS = ((1/WIDTH) + (1/HEIGHT)) / 2
def chunker(seq, size):
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
class Branch():
def __init__(self, idx, ctx, x, y, r, ang, mother=None):
#ctx.set_source_rgb(255, 0, 0)
self.nodes = [Node(ctx, x, y, r, ang, dry=True)]
#ctx.set_source_rgb(0,0, 0)
self.idx = idx
self.ctx = ctx
self.ended = False
self.ignores = []
self.first = True
self.mother = mother
def _last_node(self):
return self.nodes[-1]
def set_ignores(self, ignores):
self.ignores = ignores
def place_next(self, branches):
if not self.ended:
last = self._last_node()
next_x = last.r * math.sin(last.ang) + last.x
next_y = last.r * math.cos(last.ang) + last.y
next_r = last.r - SHRINK
# too small?
if next_r < MIN_RADIUS:
self.ended = True
return False
# did we hit canvas edge?
# if next_x + next_r > 1 or next_x - next_r < 0:
if (math.pow(next_x - 0.5, 2) + math.pow(next_y - 0.5, 2)) > math.pow(0.4, 2):
self.ended = True
return False
if next_y + next_r > 1 or next_y - next_r < 0:
self.ended = True
return False
last_nodes = self.nodes[-2:]
# did we hit another circle?
# search radius is radius of biggest possible circle + our radius
search_radius = next_r + start_r
search_box_x1 = next_x - search_radius
search_box_x2 = next_x + search_radius
search_box_y1 = next_y - search_radius
search_box_y2 = next_y + search_radius
filtered = NODE_ARRAY[NODE_ARRAY['x'] > search_box_x1]
filtered = filtered[filtered['x'] < search_box_x2]
filtered = filtered[filtered['y'] > search_box_y1]
filtered = filtered[filtered['y'] < search_box_y2]
# remove previous nodes
for ln in last_nodes:
filtered = filtered[ (filtered['x'] != ln.x) & (filtered['y'] != ln.y) ]
for possible_hit in filtered:
if circles_intersect(*possible_hit, next_x, next_y, next_r):
self.ended = True
return False
next_ang = last.ang + (random.uniform(ANGLE_RANDOM_MIN, ANGLE_RANDOM_MAX) * (1 - 40*last.r))
self.nodes.append(Node(self.ctx, next_x, next_y, next_r, next_ang))
if self.first:
self.first = False
first = self.nodes[0]
if self.mother:
self.ctx.set_operator(cairo.Operator.DEST_OVER)
circle_fill(self.ctx, first.x, first.y, first.r)
self.ctx.set_operator(cairo.Operator.OVER)
else:
circle_fill(self.ctx, first.x, first.y, first.r)
return True
def circles_intersect(x1, y1, r1, x2, y2, r2):
distance = math.sqrt(math.pow(abs(x2 - x1), 2) + math.pow(abs(y2 - y1), 2))
combined_r = r1 + r2
return distance < combined_r
class Node():
def __init__(self, ctx, x, y, r, ang, dry=False):
global NODE_ARRAY
self.x = x
self.y = y
self.r = r
self.ang = ang
if not dry:
NODE_ARRAY = numpy.append(NODE_ARRAY,
numpy.array([(x, y, r)],
dtype=[('x', 'float'), ('y', 'float'), ('r', 'float')])
)
circle_fill(ctx, x, y, r)
def __ne__(self, other):
return self.x != other.x or self.y != other.y or self.r != other.r or self.ang != other.ang
def grow_sub(ctx, branch, branches, new_subs):
# create a sub branch based on length
sub_branches = len(branch.nodes) // 8 * 2
if sub_branches == 0: return
#sub_branches = 4
#print(f'creating {sub_branches} subs')
for i in range(sub_branches):
for n in range(20): # attempts at growing branches
found_ang = False
start_node = random.choice(branch.nodes)
for a_try in range(10):
# start perpendicular to our last angle
start_angle = start_node.ang + random.choice([90, -90]) + random.uniform(-30, 30)
start_x = (start_node.r * 1.2) * math.sin(start_angle) + start_node.x
start_y = (start_node.r * 1.2) * math.cos(start_angle) + start_node.y
start_r = start_node.r * 0.8
new_branch = Branch(0, ctx, start_x, start_y, start_r, start_angle, mother=start_node)
if new_branch.place_next(branches):
found_ang = True
break
if found_ang:
break
grow_branch_until_ended(new_branch, branches)
new_branch.set_ignores(branch.nodes)
branches.append(new_branch)
new_subs.append(new_branch)
def grow_branch_until_ended(branch, branches):
while not branch.ended:
branch.place_next([b for b in branches if b != branch])
def grow_subs(ctx, subs, branches):
source = ctx.get_source()
new_subs = []
for branch in subs:
grow_sub(ctx, branch, branches, new_subs)
#for branch in new_subs:
# grow_branch_until_ended(branch, branches)
return new_subs
def main():
global start_hue
global NODE_ARRAY
for run in range(32):
random.seed()
start_hue = random.uniform(0, 1)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
ctx = cairo.Context(surface)
ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas
# place seeds
branches = []
r, g, b = colorsys.hsv_to_rgb(start_hue, 1.0, 1.0)
#r, g, b = random_color()
ctx.set_source_rgb(r, g, b)
branches.append(Branch(0, ctx, 0.5, 0.4, start_r, 180))
branches.append(Branch(1, ctx, 0.4, 0.5, start_r, 270))
branches.append(Branch(2, ctx, 0.6, 0.5, start_r, 90))
branches.append(Branch(3, ctx, 0.5, 0.6, start_r, 0))
NODE_ARRAY = numpy.array([
(0.5, 0.4, start_r),
(0.4, 0.5, start_r),
(0.6, 0.5, start_r),
(0.5, 0.6, start_r)
], dtype = [('x', 'float'), ('y', 'float'), ('r', 'float')])
# grow initial branches
print('growing initial branches')
for branch in branches:
grow_branch_until_ended(branch, branches)
subs = branches
rarity = 3 + random.randint(0, 5)
print(f'rarity: {rarity}')
try:
for x in range(rarity):
if subs == None:
return
r, g, b = colorsys.hsv_to_rgb(start_hue + x * 0.05, 1.0, 1.0)
ctx.set_source_rgb(r, g, b)
subs = grow_subs(ctx, subs, branches)
print(f'iteration {x} done')
#surface.write_to_png("out/hyphae.png") # Output to PNG
r, g, b = colorsys.hsv_to_rgb(start_hue - 0.05, 1.0, 0.2)
ctx.set_source_rgb(r, g, b)
ctx.set_operator(cairo.Operator.DEST_OVER)
circle_fill(ctx, 0.5, 0.5, 0.4)
finally:
surface.write_to_png(f"out/hyphae_{run}_{rarity}.png") # Output to PNG
print(f'run {run} complete')
if __name__ == '__main__':
main()

@ -0,0 +1,229 @@
#!/usr/bin/env python3
import cairo
import math
import random
import threading
import time
import socket
import colorsys
from utils import circle_fill
from utils import random_color
#from pixelflut import surface_to_pixelflut
WIDTH, HEIGHT = 1920, 1080
ANGLE_RANDOM_MIN = -0.6
ANGLE_RANDOM_MAX = 0.6
# how much to shrink each consecutive circle
SHRINK = 0.00002
hitmap = list()
DRAW_MAP = None
start_hue = random.uniform(0, 1)
SERVER_IP = '192.168.178.75'
#SERVER_IP = '127.0.0.1'
SERVER_PORT = 1234
#SERVER_PORT = 1337
def chunker(seq, size):
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
def surface_to_pixelflut():
global DRAW_MAP
while True:
data = DRAW_MAP.get_data()
pixels = data.hex()
x, y = 0, 0
#to_send = list()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# for chunk in chunker(pixels, 65536):
pxstr = ''
for hexpx in chunker(pixels, 8):
if x > 1919:
x = 0
y += 1
x += 1
if hexpx[6:8] == '00':
continue
pxstr += f'PX {x} {y} {hexpx[:6]}\n'
#to_send.append(pxstr)
#for px in to_send:
# s.sendall(px.encode())
print('!! socket opened !!')
s.connect((SERVER_IP, SERVER_PORT))
s.sendall(pxstr.encode())
#print(f'sent {pxstr}')
print('!! transmission to pixelflut finished !!')
class Branch():
def __init__(self, idx, ctx, x, y, r, ang):
#ctx.set_source_rgb(255, 0, 0)
self.nodes = [Node(ctx, x, y, r, ang, dry=True)]
#ctx.set_source_rgb(0,0, 0)
self.idx = idx
self.ctx = ctx
self.ended = False
self.ignores = []
self.first = True
def _last_node(self):
return self.nodes[-1]
def set_ignores(self, ignores):
self.ignores = ignores
def place_next(self, branches):
if not self.ended:
last = self._last_node()
next_x = last.r * math.sin(last.ang) + last.x
next_y = last.r * math.cos(last.ang) + last.y
next_r = last.r - SHRINK
# too small?
if next_r < 0.000000001:
self.ended = True
return False
# did we hit canvas edge?
# if next_x + next_r > 1 or next_x - next_r < 0:
if (math.pow(next_x - 0.5, 2) + math.pow(next_y - 0.5, 2)) > math.pow(0.4, 2):
self.ended = True
return False
if next_y + next_r > 1 or next_y - next_r < 0:
self.ended = True
return False
last_nodes = self.nodes[-2:]
# did we hit another circle?
for branch in branches:
for node in branch.nodes:
if node not in last_nodes and node not in self.ignores: #!= last and node != self.nodes[-2]:
if circles_intersect(node.x, node.y, node.r,
next_x, next_y, next_r):
self.ended = True
return False
next_ang = last.ang + (random.uniform(ANGLE_RANDOM_MIN, ANGLE_RANDOM_MAX) * (1 - 40*last.r))
self.nodes.append(Node(self.ctx, next_x, next_y, next_r, next_ang))
if self.first:
self.first = False
first = self.nodes[0]
circle_fill(self.ctx, first.x, first.y, first.r)
return True
def circles_intersect(x1, y1, r1, x2, y2, r2):
distance = math.sqrt(math.pow(abs(x2 - x1), 2) + math.pow(abs(y2 - y1), 2))
combined_r = r1 + r2
return distance < combined_r
class Node():
def __init__(self, ctx, x, y, r, ang, dry=False):
self.x = x
self.y = y
self.r = r
self.ang = ang
if not dry:
circle_fill(ctx, x, y, r)
def __ne__(self, other):
return self.x != other.x or self.y != other.y or self.r != other.r or self.ang != other.ang
def grow_sub(ctx, branch, branches, new_subs):
# create a sub branch based on length
sub_branches = len(branch.nodes) // 7 * 2
if sub_branches == 0: return
#sub_branches = 4
#print(f'creating {sub_branches} subs')
for i in range(sub_branches):
for n in range(60): # attempts at growing branches
start_node = random.choice(branch.nodes)
# start perpendicular to our last angle
start_angle = start_node.ang + random.choice([90, -90]) + random.uniform(-30, 30)
start_x = (start_node.r * 1.2) * math.sin(start_angle) + start_node.x
start_y = (start_node.r * 1.2) * math.cos(start_angle) + start_node.y
start_r = start_node.r * 0.8
new_branch = Branch(0, ctx, start_x, start_y, start_r, start_angle)
if new_branch.place_next(branches):
break
new_branch.set_ignores(branch.nodes)
branches.append(new_branch)
new_subs.append(new_branch)
def grow_branch_until_ended(branch, branches):
while not branch.ended:
branch.place_next([b for b in branches if b != branch])
def grow_subs(ctx, subs, branches):
source = ctx.get_source()
new_subs = []
#threads = list()
print('spawning sub growing threads')
for branch in subs:
# x = threading.Thread(target=grow_sub, args=(ctx, branch, branches, new_subs))
# threads.append(x)
# x.start()
grow_sub(ctx, branch, branches, new_subs)
#for tidx, thread in enumerate(threads):
# thread.join()
print('all threads finished')
print('starting place_next threads')
#pl_threads = list()
for branch in new_subs:
grow_branch_until_ended(branch, branches)
print('place_next done')
#while not all([branch.ended for branch in new_subs]):
# for branch in new_subs:
# branch.place_next([b for b in branches if b != branch])
return new_subs
def main():
global DRAW_MAP
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
ctx = cairo.Context(surface)
ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas
# place seeds
branches = []
#for b in range(6):
# start_x = random.uniform(0.2, 0.8)
# start_y = random.uniform(0.2, 0.8)
start_r = 0.01
r, g, b = colorsys.hsv_to_rgb(start_hue, 1.0, 1.0)
#r, g, b = random_color()
ctx.set_source_rgb(r, g, b)
# start_angle = random.randint(0, 360)
# branches.append(Branch(b, ctx, start_x, start_y, start_r, start_angle))
branches.append(Branch(0, ctx, 0.5, 0.4, start_r, 180))
branches.append(Branch(1, ctx, 0.4, 0.5, start_r, 270))
branches.append(Branch(2, ctx, 0.6, 0.5, start_r, 90))
branches.append(Branch(3, ctx, 0.5, 0.6, start_r, 0))
# grow initial branches
print('growing initial branches')
while not all([b.ended for b in branches]):
for branch in branches:
branch.place_next(branches)
# start branching off
#subs = []
subs = branches
DRAW_MAP = surface
t = threading.Thread(target=surface_to_pixelflut, daemon=True)
t.start()
try:
for x in range(8):
if subs == None:
return
r, g, b = colorsys.hsv_to_rgb(start_hue + x * 0.05, 1.0, 1.0)
#r, g, b = random_color()
ctx.set_source_rgb(r, g, b)
subs = grow_subs(ctx, subs, branches)
print(f'iteration {x} done, sending to pixelflut')
DRAW_MAP = surface
#surface.write_to_png("out/hyphae.png") # Output to PNG
finally:
surface.write_to_png("out/hyphae.png") # Output to PNG
sys.exit(0)
if __name__ == '__main__':
main()

@ -0,0 +1,62 @@
#!/usr/bin/env python3
import cairo
import math
import random
from utils import circle_fill
from utils import draw_crater
from utils import random_color
from utils import moon_shade
WIDTH, HEIGHT = 100, 100
def main():
import sys
seed = sys.argv[1]
random.seed(seed)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
ctx = cairo.Context(surface)
ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas
ctx.set_source_rgb(0.9, 0.9, 0.9)
# draw "full" moon
circle_fill(ctx, 0.5, 0.5, 0.5)
# make sure we only draw "inside"
ctx.set_operator(cairo.Operator.ATOP)
# draw craters
ctx.set_source_rgb(0.5, 0.5, 0.5)
for c in range(30):
#c_col = random.uniform(0.4, 0.6)
#ctx.set_source_rgb(c_col, c_col, c_col)
c_x = random.uniform(0.0, 1.0)
c_y = random.uniform(0.0, 1.0)
c_r = random.uniform(0.01, 0.1)
draw_crater(ctx, c_x, c_y, c_r)
# draw "aura"
a_r, a_g, a_b = random_color()
p = cairo.RadialGradient(0.5, 0.5, 0.25, 0.5, 0.5, 0.5)
#p.add_color_stop_rgba(0.0, 0.9, 0.9, 0.9, 0.0)
p.add_color_stop_rgba(0.0, a_r, a_g, a_b, 0.0)
p.add_color_stop_rgba(0.3, a_r, a_g, a_b, 0.0)
p.add_color_stop_rgba(1.0, a_r, a_g, a_b, 0.8)
ctx.set_source(p)
ctx.arc(0.5, 0.5, 0.5, 0, math.pi*2)
#ctx.arc(0.5, 0.5, 0.3, 0, math.pi*2)
ctx.fill()
# draw "shade" of the phase
ctx.set_source_rgba(0.1, 0.1, 0.1, 0.95)
phase_pos = random.uniform(-1.2, 1.2)
#circle_fill(ctx, phase_pos, 0.5, 0.5)
moon_shade(ctx, phase_pos)
surface.write_to_png(f"nft/{seed}_moon.png") # Output to PNG
if __name__ == '__main__':
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 KiB

@ -0,0 +1,37 @@
#!/usr/bin/env python3
import sys
import io
import socket
sys.path.append('..')
from waves import create_wpotd
#SERVER_IP = '192.168.178.75'
SERVER_IP = '127.0.0.1'
SERVER_PORT = 1234
def chunker(seq, size):
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
def surface_to_pixelflut():
global DRAW_MAP
while True:
data = DRAW_MAP.get_data()
pixels = data.hex()
x, y = 0, 0
to_send = list()
for hexpx in chunker(pixels, 8):
if x > 1919:
x = 0
y += 1
x += 1
if hexpx[6:8] == '00':
continue
pxstr = f'PX {x} {y} {hexpx[:6]}\n'
to_send.append(pxstr)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((SERVER_IP, SERVER_PORT))
print('!! socket opened !!')
for px in to_send:
s.sendall(px.encode())
#print(f'sent {pxstr}')
print('!! transmission to pixelflut finished !!')

@ -5,11 +5,46 @@ def circle(ctx,x,y,r):
ctx.arc(x,y,r,0,math.pi*2.)
ctx.stroke()
def circle_fill(ctx,x,y,r):
ctx.arc(x,y,r,0,math.pi*2.)
ctx.fill()
def draw_crater(ctx,x,y,r):
for n in range(3):
off_x = random.uniform(-0.01, 0.01)
off_y = random.uniform(-0.01, 0.01)
ctx.arc(x + off_x, y + off_y, r, 0, math.pi*2.)
ctx.fill()
def moon_shade(ctx, phase, nothern=True):
#phase=-0.4
#x_max = 0.7
x_max = 1.
# the shadow always has to "hug" one side - pick which
ctx.move_to(0.5, 0.0)
if phase > 0:
ctx.curve_to(-0.2, 0, -0.2, 1, 0.5, 1)
elif phase < 0:
ctx.curve_to(1.2, 0, 1.2, 1, 0.5, 1)
else:
return
#ctx.close_path()
#ctx.fill()
#ctx.move_to(0.5, 0.0)
#ctx.curve_to(x_max*phase, 0.5-(0.5*phase), x_max*phase, 0.5+(0.5*phase), 0.5, 1)
#ctx.curve_to(0.5 + (x_max*phase), 0.5+(0.5*phase), 0.5+ (x_max*phase), 0.5-(0.5*phase), 0.5, 0)
# helper x is the same for both points
h_x = abs(x_max * phase)
h_y = abs(h_x - 0.5)
#y_c = (phase * 0.5)
#ctx.curve_to(x_max*phase, 0.5+abs(0.5*phase-0.5), (x_max*phase), 0.5-abs(0.5*phase-0.5), 0.5, 0)
ctx.curve_to(h_x, 0.5 + h_y, h_x, 0.5-h_y, 0.5, 0)
#ctx.close_path()
ctx.fill()
def random_color():
red = random.uniform(0, 1)

@ -2,97 +2,79 @@
import cairo
import math
import datetime
from datetime import datetime
import calendar
import random
from utils import random_color
# dimensions of the output image
WIDTH, HEIGHT = 1920, 1080
# how much should the phases be offset?
WAVE_OFFSET = math.pi / random.choice([1, 2, 4]) #-1.9
# amplitude of the sine wave
#AMPLITUDE = 9
# only 1 color with shades?
MONOCHROME = True
# works only if monochrome is set - uses todays date as base for the color
DATE_BASED_COLOR = True
DATE_BASED_AMPLITUDE = True
DATE_BASED_COUNT = True
# background black? White otherwise:
DARK_BG = True
import colorsys
import argparse
# precision of the calculation
PRECISION = 10000
def days_color(date):
import colorsys
def get_color_from_date(date: datetime) -> tuple[float, float, float]:
"""Return a color based on the progress through the year."""
# a day between 1 and 365 (inclusive)
today = date.timetuple().tm_yday
year = date.year
days_in_year = 365 + calendar.isleap(year)
days_in_year = 365 + calendar.isleap(date.year)
# between 0 and 1, how far through the year are we?
progress = today/days_in_year
progress = today / days_in_year
return colorsys.hsv_to_rgb(progress, 1, 0.9)
def days_amp(date, waves):
day = date.day
def get_amplitude_from_date(date: datetime, waves) -> float:
"""Return the amplitude of waves, based on progress through the month."""
days_in_month = calendar.monthrange(date.year, date.month)[1]
max_amp = 1/waves/2
return day/days_in_month * max_amp
max_amp = 1 / waves / 2
return date.day / days_in_month * max_amp
def days_count(date):
return date.month
def create_wpotd(output):
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
def create_wpotd(
width: int,
height: int,
frequency: int,
wave_offset: float,
date: datetime = datetime.now(),
dark: bool = True,
) -> cairo.ImageSurface:
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
ctx = cairo.Context(surface)
ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas
#ctx.set_antialias(cairo.Antialias.BEST)
ctx.scale(width, height) # Normalizing the canvas
# ctx.set_antialias(cairo.Antialias.BEST)
step_size = 1/PRECISION
lastpoints = [(x/PRECISION, 0) for x in range(PRECISION+1)]
lastpoints = [(x / PRECISION, 0) for x in range(PRECISION + 1)]
#date = datetime.datetime.strptime('2021-06-30', '%Y-%m-%d')
date = datetime.datetime.today()
frequency = random.randint(10, 40)
if DATE_BASED_COUNT:
waves = days_count(date)
else:
waves = 12
if DATE_BASED_AMPLITUDE:
amplitude = days_amp(date, waves)
else:
amplitude = 25
waves = date.month
amplitude = get_amplitude_from_date(date, waves)
r, g, b = get_color_from_date(date)
alpha_step = 1 / waves
if MONOCHROME:
if DATE_BASED_COLOR:
r, g, b = days_color(date) #datetime.datetime.now())
# background color
if dark:
ctx.set_source_rgb(0, 0, 0)
else:
r, g, b = random_color()
alpha_step = 1/waves
if DARK_BG:
# make bg black
ctx.set_source_rgb(255, 255, 255)
ctx.rectangle(0, 0, 1, 1)
ctx.set_source_rgb(0, 0, 0)
ctx.fill()
wave_height = 1/waves
for num in range(waves+1):
if not MONOCHROME:
r, g, b = random_color()
wave_height = 1 / waves
step_size = 1 / PRECISION
for wave_index in range(waves + 1):
points = []
x = 0
while x < 1:
y = amplitude * math.sin(frequency * x + (num * WAVE_OFFSET) )
points.append((x, ( y + (0.5+num)*wave_height)))
# step along, create points along the wave
y = amplitude * math.sin(frequency * x + (wave_index * wave_offset))
points.append((x, (y + (0.5 + wave_index) * wave_height)))
x += step_size
#print(f'Draw {len(points)} points for curve {num}')
if not MONOCHROME:
ctx.set_source_rgb(r, g, b)
# print(f'Draw {len(points)} points for curve {num}')
else:
ctx.set_source_rgba(r, g, b, 1 - (alpha_step * num)) # make more transparent toward bottom
# make more transparent toward bottom
ctx.set_source_rgba(r, g, b, 1 - (alpha_step * wave_index))
# draw waves
ctx.move_to(*points[0])
for p in points[1:]:
@ -104,11 +86,45 @@ def create_wpotd(output):
ctx.line_to(*points[0])
ctx.fill()
lastpoints = points
return surface
surface.write_to_png(output) # Output to PNG
def main():
create_wpotd('out/waves.png')
parser = argparse.ArgumentParser()
parser.add_argument("width", type=int, help="Width of the image")
parser.add_argument("height", type=int, help="Height of the image")
parser
parser.add_argument("--dark", help="Draw on dark background", action="store_true")
parser.add_argument(
"-o",
"--offset",
type=float,
help="How much the waves should be offset to each other",
)
parser.add_argument("-f", "--frequency", type=int, help="Frequency of the waves")
parser.add_argument(
"--stdout", help="Write output image to stdout", action="store_true"
)
args = parser.parse_args()
print(args)
if not args.offset:
args.offset = math.pi / random.choice([1, 2, 4])
if not args.frequency:
args.frequency = random.randint(10, 40)
output = create_wpotd(
args.width,
args.height,
dark=args.dark,
wave_offset=args.offset,
frequency=args.frequency,
)
if args.stdout:
import sys
output.write_to_png(sys.stdout.buffer)
else:
output.write_to_png("out/waves.png")
if __name__ == '__main__':
if __name__ == "__main__":
main()

@ -1,4 +1,12 @@
#!/usr/bin/env python3
print('Content-Type: image/png')
print(open('out/waves.png', 'rb').read())
import sys
import io
sys.path.append('..')
from waves import create_wpotd
buf = io.BytesIO()
create_wpotd(buf)
sys.stdout.write('Content-Type: image/png\r\n\r\n')
sys.stdout.flush()
sys.stdout.buffer.write(buf.getvalue())

Loading…
Cancel
Save