RRS First version
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"""Create original illustrative knit textures, not photographs of RRS products.
|
||||
Requires Pillow and NumPy. Generated assets are committed; runtime needs neither.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import math
|
||||
import random
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFilter
|
||||
|
||||
OUTPUT = Path(__file__).resolve().parents[1] / 'public' / 'images'
|
||||
OUTPUT.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def texture(name, spacing, base, seed):
|
||||
rng = random.Random(seed)
|
||||
width, height = 1600, 1200
|
||||
image = Image.new('RGB', (width, height), tuple(round(c * .7) for c in base))
|
||||
draw = ImageDraw.Draw(image)
|
||||
for row in range(-2, round(height / (spacing * .72)) + 3):
|
||||
for column in range(-2, width // spacing + 3):
|
||||
x = column * spacing + math.sin(row * .16) * spacing * .16
|
||||
y = row * spacing * .72
|
||||
tone = rng.uniform(.91, 1.05)
|
||||
for side in (-1, 1):
|
||||
points = []
|
||||
for step in range(35):
|
||||
t = step / 34
|
||||
px = x + side * spacing * (.04 + .43 * (1 - t) + .07 * math.sin(t * math.pi))
|
||||
py = y + spacing * (t * .95 - .15)
|
||||
points.append((px, py))
|
||||
draw.line([(px + 3, py + 4) for px, py in points], fill=tuple(round(c * .55) for c in base), width=round(spacing * .36))
|
||||
draw.line(points, fill=tuple(min(255, round(c * tone * .84)) for c in base), width=round(spacing * .32))
|
||||
for strand in range(11):
|
||||
offset = (strand - 5) * spacing * .027
|
||||
fibre = [(px + offset + math.sin(i * .9 + strand) * .7, py) for i, (px, py) in enumerate(points)]
|
||||
light = tone * (.78 + .24 * math.sin(strand * .28))
|
||||
draw.line(fibre, fill=tuple(min(255, round(c * light)) for c in base), width=max(1, spacing // 32))
|
||||
pixels = np.asarray(image).astype(float)
|
||||
yy, xx = np.mgrid[0:height, 0:width]
|
||||
folds = .91 + .14 * np.sin(xx / 210 + yy / 380) + .05 * np.sin(xx / 82 - yy / 230)
|
||||
noise = np.random.default_rng(seed).normal(0, 2.1, (height, width))
|
||||
pixels = np.clip(pixels * folds[:, :, None] + noise[:, :, None], 0, 255).astype('uint8')
|
||||
Image.fromarray(pixels).filter(ImageFilter.GaussianBlur(.3)).save(OUTPUT / name, quality=90, optimize=True)
|
||||
|
||||
|
||||
texture('knit-natural.jpg', 70, (218, 205, 181), 21)
|
||||
texture('knit-fine.jpg', 27, (221, 214, 197), 42)
|
||||
texture('knit-structured.jpg', 108, (180, 170, 147), 63)
|
||||
Reference in New Issue
Block a user