Created
March 19, 2025 01:57
-
-
Save ento/2e369d418b5dff7b7fdf7bf76260616e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Generate a set of emoji images depicting various points on a hill. | |
Assumes pillow is available | |
https://pypi.org/project/pillow/ | |
Image size is based on the size recommended by Notion | |
""" | |
import math | |
import sys | |
from PIL import Image, ImageDraw | |
def hill_curve_func(width: int, height: int, x: float) -> float: | |
x_center = width // 2 | |
bottom_margin = width // 6 | |
# Primary Gaussian curve | |
primary_curve_height = width * 1.2 | |
primary_curve_bell_width = width // 6 | |
# Subtract a smaller Gaussian curve to flatten the primary curve a bit | |
damper_curve_height = width // 2 | |
damper_curve_bell_width = width // 8 | |
return ( | |
height | |
- bottom_margin | |
- ( | |
primary_curve_height * math.e ** (-(((x - x_center) ** 2 / (2 * primary_curve_bell_width**2)))) | |
- damper_curve_height * math.e ** (-(((x - x_center) ** 2 / (2 * damper_curve_bell_width**2)))) | |
) | |
) | |
def draw_hill_curve(d: ImageDraw.ImageDraw): | |
width, height = d.im.size | |
for x1 in range(1, width): | |
x0 = x1 - 1 | |
y0 = hill_curve_func(width, height, x0) | |
y1 = hill_curve_func(width, height, x1) | |
d.line((x0, y0, x1, y1), fill=0, width=width // 30) | |
def draw_progress_dot(d: ImageDraw.ImageDraw, progress: float): | |
""" | |
:param progress: A float between 0 and 1, inclusive. | |
""" | |
width, height = d.im.size | |
x = width * progress | |
y = hill_curve_func(width, height, x) | |
radius = width // 9 | |
d.circle((x, y), radius, fill=(0, 168, 211), outline=None, width=0) | |
def make_emoji(width: int, height: int, progress: float): | |
""" | |
:param progress: A float between 0 and 1, inclusive. | |
""" | |
# To draw a smooth hill curve, we draw on a bigger image and scale it down | |
scale = 8 | |
upscaled_width, upscaled_height = width * scale, height * scale | |
image = Image.new("RGB", (upscaled_width, upscaled_height), (255, 255, 255)) | |
draw_upscaled = ImageDraw.Draw(image) | |
draw_hill_curve(draw_upscaled) | |
# Draw the progress dot | |
final_image = image.resize((width, height), resample=Image.LANCZOS) | |
draw_final = ImageDraw.Draw(final_image) | |
draw_progress_dot(draw_final, progress=progress) | |
return final_image | |
def main(): | |
emoji_width = 280 | |
emoji_height = 280 | |
dot_count = 7 | |
for i in range(dot_count): | |
progress = (1 + i) / (dot_count + 1) | |
emoji = make_emoji(emoji_width, emoji_height, progress) | |
with open(f"hill_{i + 1}.png", "wb") as f: | |
emoji.save(f, "PNG") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment