Initial commit
This commit is contained in:
21
scratch/analyze_bag_colors.py
Normal file
21
scratch/analyze_bag_colors.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from PIL import Image
|
||||
|
||||
def analyze_bag_colors(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
|
||||
# Let's inspect columns near the logo, e.g. x = 800 (just left of logo)
|
||||
# and x = 975 (just right of logo)
|
||||
print("Purple bag colors near logo:")
|
||||
colors = {}
|
||||
for y in range(160, 410, 10):
|
||||
# Left side
|
||||
colors[pixels[800, y]] = colors.get(pixels[800, y], 0) + 1
|
||||
# Right side
|
||||
colors[pixels[970, y]] = colors.get(pixels[970, y], 0) + 1
|
||||
|
||||
for color, count in sorted(colors.items(), key=lambda x: x[1], reverse=True)[:10]:
|
||||
print(f"Color: {color}, count: {count}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_bag_colors("public/images/slider-courier-mask-purple.png")
|
||||
32
scratch/analyze_coords.py
Normal file
32
scratch/analyze_coords.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from PIL import Image
|
||||
|
||||
def analyze_coords(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
# Track the x-coordinates of white pixels (r=255, g=255, b=255, a>0)
|
||||
white_x = []
|
||||
purple_x = []
|
||||
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a > 0:
|
||||
if r == 255 and g == 255 and b == 255:
|
||||
white_x.append(x)
|
||||
elif r == 102 and g == 37 and b == 130:
|
||||
purple_x.append(x)
|
||||
|
||||
if white_x:
|
||||
print(f"White pixels: count={len(white_x)}, x-range=[{min(white_x)}, {max(white_x)}]")
|
||||
else:
|
||||
print("No white pixels found.")
|
||||
|
||||
if purple_x:
|
||||
print(f"Purple pixels: count={len(purple_x)}, x-range=[{min(purple_x)}, {max(purple_x)}]")
|
||||
else:
|
||||
print("No purple pixels found.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_coords("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781942586218.png")
|
||||
47
scratch/analyze_first_logo.py
Normal file
47
scratch/analyze_first_logo.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from PIL import Image
|
||||
|
||||
def analyze_first_logo(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
print("Mode:", img.mode)
|
||||
print("Size:", img.size)
|
||||
|
||||
# Bounding box for icon on the left (x < 60)
|
||||
xs_icon = []
|
||||
ys_icon = []
|
||||
for x in range(60):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
# Purple icon has color like (102, 37, 130)
|
||||
if a > 0 and (r < 150 and g < 100 and b > 100):
|
||||
xs_icon.append(x)
|
||||
ys_icon.append(y)
|
||||
|
||||
if xs_icon:
|
||||
print(f"First Logo Icon bounding box:")
|
||||
print(f"X: {min(xs_icon)} to {max(xs_icon)} (width={max(xs_icon) - min(xs_icon) + 1})")
|
||||
print(f"Y: {min(ys_icon)} to {max(ys_icon)} (height={max(ys_icon) - min(ys_icon) + 1})")
|
||||
else:
|
||||
print("No purple pixels found in left region.")
|
||||
|
||||
# Bounding box for white text in the middle/right (x >= 60)
|
||||
xs_text = []
|
||||
ys_text = []
|
||||
for x in range(60, width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
# White text is transparent white or opaque white
|
||||
if a > 0 and (r > 240 and g > 240 and b > 240):
|
||||
xs_text.append(x)
|
||||
ys_text.append(y)
|
||||
|
||||
if xs_text:
|
||||
print(f"First Logo Text bounding box:")
|
||||
print(f"X: {min(xs_text)} to {max(xs_text)} (width={max(xs_text) - min(xs_text) + 1})")
|
||||
print(f"Y: {min(ys_text)} to {max(ys_text)} (height={max(ys_text) - min(ys_text) + 1})")
|
||||
else:
|
||||
print("No white pixels found in right region.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_first_logo("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781948467684.png")
|
||||
120
scratch/apply_first_logo_branding.py
Normal file
120
scratch/apply_first_logo_branding.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import os
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
def apply_first_logo_branding():
|
||||
first_logo_path = "/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781948467684.png"
|
||||
# Base rider image is the one with the black badge we created (v3)
|
||||
rider_image_v3 = "public/images/slider-courier-mask-purple-v3.png"
|
||||
rider_image_v4 = "public/images/slider-courier-mask-purple-v4.png"
|
||||
|
||||
# 1. Load the first logo (has white text and transparent background)
|
||||
logo_img = Image.open(first_logo_path).convert("RGBA")
|
||||
logo_w, logo_h = logo_img.size
|
||||
|
||||
# 2. Save transparent copy as logo.png (white text, transparent background)
|
||||
logo_img.save("public/logo.png", "PNG")
|
||||
logo_img.save("public/images/logo.png", "PNG")
|
||||
print("Saved logo.png (transparent white logo) to public/ and public/images/")
|
||||
|
||||
# 3. Create transparent purple logo for Navbar (convert white text to purple #662582 / RGB 102, 37, 130)
|
||||
logo_purple = Image.new("RGBA", (logo_w, logo_h))
|
||||
pixels_orig = logo_img.load()
|
||||
pixels_purple = logo_purple.load()
|
||||
|
||||
for x in range(logo_w):
|
||||
for y in range(logo_h):
|
||||
r, g, b, a = pixels_orig[x, y]
|
||||
if a > 0:
|
||||
# If pixel is white/near white (R > 230, G > 230, B > 230)
|
||||
if r > 230 and g > 230 and b > 230:
|
||||
# Convert to purple, preserving original alpha channel
|
||||
pixels_purple[x, y] = (102, 37, 130, a)
|
||||
else:
|
||||
pixels_purple[x, y] = (r, g, b, a)
|
||||
else:
|
||||
pixels_purple[x, y] = (0, 0, 0, 0)
|
||||
|
||||
logo_purple.save("public/logo-purple.png", "PNG")
|
||||
logo_purple.save("public/images/logo-purple.png", "PNG")
|
||||
print("Saved logo-purple.png (transparent purple logo) to public/ and public/images/")
|
||||
|
||||
# 4. Create transparent pure white logo (convert all logo pixels to white, preserving alpha)
|
||||
logo_white = Image.new("RGBA", (logo_w, logo_h))
|
||||
pixels_white = logo_white.load()
|
||||
|
||||
for x in range(logo_w):
|
||||
for y in range(logo_h):
|
||||
r, g, b, a = pixels_orig[x, y]
|
||||
if a > 0:
|
||||
pixels_white[x, y] = (255, 255, 255, a)
|
||||
else:
|
||||
pixels_white[x, y] = (0, 0, 0, 0)
|
||||
|
||||
# 5. Crop and create Favicon from the circle icon
|
||||
# Bounding box of the solid circle icon: X: 0 to 39, Y: 4 to 43 (size 40x40)
|
||||
icon_crop = logo_img.crop((0, 4, 40, 44))
|
||||
icon_w, icon_h = icon_crop.size
|
||||
|
||||
# Draw a solid white circle background behind the favicon
|
||||
favicon_img = Image.new("RGBA", (40, 40), (0, 0, 0, 0))
|
||||
draw_fav = ImageDraw.Draw(favicon_img)
|
||||
|
||||
# Draw solid white circle matching the border of the icon
|
||||
margin = 1
|
||||
draw_fav.ellipse(
|
||||
[margin, margin, 40 - margin, 40 - margin],
|
||||
fill=(255, 255, 255, 255)
|
||||
)
|
||||
|
||||
# Paste the purple logo icon on top of the white circle background
|
||||
favicon_img.paste(icon_crop, (0, 0), icon_crop)
|
||||
|
||||
# Resize to standard sizes and save
|
||||
favicon_32 = favicon_img.resize((32, 32), Image.Resampling.LANCZOS)
|
||||
favicon_48 = favicon_img.resize((48, 48), Image.Resampling.LANCZOS)
|
||||
|
||||
# Save favicon.ico to public/ and src/app/
|
||||
favicon_32.save("public/favicon.ico", format="ICO", sizes=[(32, 32), (48, 48)])
|
||||
favicon_32.save("src/app/favicon.ico", format="ICO", sizes=[(32, 32), (48, 48)])
|
||||
|
||||
# Save PNG versions
|
||||
favicon_48.save("public/favicon.png", "PNG")
|
||||
favicon_48.save("public/apple-icon.png", "PNG")
|
||||
print("Saved favicon.ico, favicon.png, and apple-icon.png to public/ and src/app/")
|
||||
|
||||
# 6. Overlay the new white logo onto the delivery rider's backpack
|
||||
rider_img = Image.open(rider_image_v3).convert("RGBA")
|
||||
|
||||
# Draw a fresh black rounded rectangle to clear the previous logo inside the badge
|
||||
# Center on the bag at x = 887, y = 270
|
||||
badge_w = 148
|
||||
badge_h = 38
|
||||
badge_left = 887 - (badge_w // 2)
|
||||
badge_top = 270 - (badge_h // 2)
|
||||
badge_right = badge_left + badge_w
|
||||
badge_bottom = badge_top + badge_h
|
||||
|
||||
draw_rider = ImageDraw.Draw(rider_img)
|
||||
draw_rider.rounded_rectangle(
|
||||
[badge_left, badge_top, badge_right, badge_bottom],
|
||||
radius=8,
|
||||
fill=(18, 2, 23, 255) # matches --brand-dark
|
||||
)
|
||||
|
||||
# Resize the new white Nearle logo (original ratio 275x45 -> width 120, height 20)
|
||||
logo_w = 120
|
||||
logo_h = 20
|
||||
resized_white_logo = logo_white.resize((logo_w, logo_h), Image.Resampling.LANCZOS)
|
||||
|
||||
logo_left = 887 - (logo_w // 2)
|
||||
logo_top = 270 - (logo_h // 2)
|
||||
|
||||
# Paste logo on top of the black badge
|
||||
rider_img.paste(resized_white_logo, (logo_left, logo_top), resized_white_logo)
|
||||
|
||||
# Save output
|
||||
rider_img.save(rider_image_v4, "PNG")
|
||||
print(f"Created updated rider image with solid logo at {rider_image_v4}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
apply_first_logo_branding()
|
||||
41
scratch/brighten_map.py
Normal file
41
scratch/brighten_map.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from PIL import Image
|
||||
|
||||
def brighten_alpha(input_path, output_path):
|
||||
img = Image.open(input_path).convert("RGBA")
|
||||
width, height = img.size
|
||||
pixels = img.load()
|
||||
|
||||
# First, find the maximum alpha value in the image
|
||||
max_alpha = 0
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a > max_alpha:
|
||||
max_alpha = a
|
||||
|
||||
print(f"Original max alpha: {max_alpha}")
|
||||
if max_alpha == 0:
|
||||
print("Image is completely transparent!")
|
||||
return
|
||||
|
||||
# Scale alpha to make max_alpha equal to 255
|
||||
scale_factor = 255.0 / max_alpha
|
||||
changed_count = 0
|
||||
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a > 0:
|
||||
new_a = min(int(a * scale_factor), 255)
|
||||
# Keep color as white, but set scaled alpha
|
||||
pixels[x, y] = (255, 255, 255, new_a)
|
||||
changed_count += 1
|
||||
|
||||
img.save(output_path, "PNG")
|
||||
print(f"Successfully scaled alpha for {changed_count} pixels and saved to {output_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
brighten_alpha(
|
||||
"public/images/slider-glob.png",
|
||||
"public/images/slider-glob.png"
|
||||
)
|
||||
10
scratch/crop_bag.py
Normal file
10
scratch/crop_bag.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from PIL import Image
|
||||
|
||||
def crop_bag(path, out_path):
|
||||
img = Image.open(path)
|
||||
cropped = img.crop((800, 130, 980, 440))
|
||||
cropped.save(out_path)
|
||||
print(f"Cropped bag saved to {out_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
crop_bag("public/images/slider-courier-mask-purple.png", "public/images/cropped_bag.png")
|
||||
27
scratch/find_icon_bounds.py
Normal file
27
scratch/find_icon_bounds.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from PIL import Image
|
||||
|
||||
def find_icon_bounds(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
xs = []
|
||||
ys = []
|
||||
|
||||
for x in range(150): # Look at left side only
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
# Detect purple pixels (not white background)
|
||||
if r < 150 and g < 100 and b > 100:
|
||||
xs.append(x)
|
||||
ys.append(y)
|
||||
|
||||
if xs:
|
||||
print(f"Icon bounding box:")
|
||||
print(f"X: {min(xs)} to {max(xs)} (width={max(xs) - min(xs) + 1})")
|
||||
print(f"Y: {min(ys)} to {max(ys)} (height={max(ys) - min(ys) + 1})")
|
||||
else:
|
||||
print("No purple pixels found in left region.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
find_icon_bounds("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png")
|
||||
27
scratch/find_icon_bounds_v2.py
Normal file
27
scratch/find_icon_bounds_v2.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from PIL import Image
|
||||
|
||||
def find_icon_bounds_v2(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
xs = []
|
||||
ys = []
|
||||
|
||||
for x in range(150): # Look at left side only
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
# Any pixel that is NOT the white background (RGB is not all high)
|
||||
if r < 240 or g < 240 or b < 240:
|
||||
xs.append(x)
|
||||
ys.append(y)
|
||||
|
||||
if xs:
|
||||
print(f"Icon bounding box (V2):")
|
||||
print(f"X: {min(xs)} to {max(xs)} (width={max(xs) - min(xs) + 1})")
|
||||
print(f"Y: {min(ys)} to {max(ys)} (height={max(ys) - min(ys) + 1})")
|
||||
else:
|
||||
print("No non-white pixels found in left region.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
find_icon_bounds_v2("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png")
|
||||
28
scratch/find_logo_coords.py
Normal file
28
scratch/find_logo_coords.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from PIL import Image
|
||||
|
||||
def find_logo_coords(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
# We look for white pixels in the region x > 700 and y < 600
|
||||
white_pixels = []
|
||||
|
||||
for x in range(700, width):
|
||||
for y in range(100, 600):
|
||||
r, g, b, a = pixels[x, y]
|
||||
# White or near white text
|
||||
if a > 200 and r > 240 and g > 240 and b > 240:
|
||||
white_pixels.append((x, y))
|
||||
|
||||
if white_pixels:
|
||||
xs = [p[0] for p in white_pixels]
|
||||
ys = [p[1] for p in white_pixels]
|
||||
print(f"GOMOTO logo bounding box:")
|
||||
print(f"X: {min(xs)} to {max(xs)} (width={max(xs) - min(xs) + 1})")
|
||||
print(f"Y: {min(ys)} to {max(ys)} (height={max(ys) - min(ys) + 1})")
|
||||
else:
|
||||
print("No white pixels found in target region.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
find_logo_coords("public/images/slider-courier-mask-purple.png")
|
||||
9
scratch/get_dimensions.py
Normal file
9
scratch/get_dimensions.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from PIL import Image
|
||||
|
||||
def get_dimensions(path):
|
||||
img = Image.open(path)
|
||||
print("Mode:", img.mode)
|
||||
print("Size:", img.size)
|
||||
|
||||
if __name__ == "__main__":
|
||||
get_dimensions("public/images/slider-courier-mask-purple.png")
|
||||
24
scratch/inspect_glob.py
Normal file
24
scratch/inspect_glob.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from PIL import Image
|
||||
|
||||
def inspect_image(path):
|
||||
img = Image.open(path)
|
||||
print("Mode:", img.mode)
|
||||
print("Size:", img.size)
|
||||
|
||||
# Check some pixels
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
color_counts = {}
|
||||
for x in range(0, width, max(1, width // 20)):
|
||||
for y in range(0, height, max(1, height // 20)):
|
||||
r, g, b, a = pixels[x, y]
|
||||
color = (r, g, b, a)
|
||||
color_counts[color] = color_counts.get(color, 0) + 1
|
||||
|
||||
print("Sample pixels:")
|
||||
for color, count in sorted(color_counts.items(), key=lambda x: x[1], reverse=True)[:10]:
|
||||
print(f"Color: {color}, count: {count}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspect_image("public/images/slider-glob.png")
|
||||
28
scratch/inspect_icon_pixels.py
Normal file
28
scratch/inspect_icon_pixels.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from PIL import Image
|
||||
|
||||
def inspect_icon_pixels(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
non_bg_coords = []
|
||||
|
||||
for x in range(150):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
# Check if it is NOT white background (defining background as r >= 250, g >= 250, b >= 250)
|
||||
is_bg = (r >= 250 and g >= 250 and b >= 250)
|
||||
if not is_bg:
|
||||
non_bg_coords.append((x, y))
|
||||
|
||||
if non_bg_coords:
|
||||
xs = [p[0] for p in non_bg_coords]
|
||||
ys = [p[1] for p in non_bg_coords]
|
||||
print(f"Non-background bounding box on left:")
|
||||
print(f"X: {min(xs)} to {max(xs)} (width={max(xs) - min(xs) + 1})")
|
||||
print(f"Y: {min(ys)} to {max(ys)} (height={max(ys) - min(ys) + 1})")
|
||||
else:
|
||||
print("All pixels in the left region are background.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspect_icon_pixels("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png")
|
||||
24
scratch/inspect_logo.py
Normal file
24
scratch/inspect_logo.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from PIL import Image
|
||||
|
||||
def inspect_logo(path):
|
||||
img = Image.open(path)
|
||||
print("Mode:", img.mode)
|
||||
print("Size:", img.size)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
# Check what colors exist in the image
|
||||
colors = {}
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a > 0:
|
||||
color = (r, g, b, a)
|
||||
colors[color] = colors.get(color, 0) + 1
|
||||
|
||||
print("Opaque / Semi-transparent pixels color counts (top 15):")
|
||||
for color, count in sorted(colors.items(), key=lambda x: x[1], reverse=True)[:15]:
|
||||
print(f"Color: {color}, count: {count}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspect_logo("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781942586218.png")
|
||||
23
scratch/inspect_new_logo.py
Normal file
23
scratch/inspect_new_logo.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from PIL import Image
|
||||
|
||||
def inspect_new_logo(path):
|
||||
img = Image.open(path)
|
||||
print("Mode:", img.mode)
|
||||
print("Size:", img.size)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
colors = {}
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a > 0:
|
||||
color = (r, g, b, a)
|
||||
colors[color] = colors.get(color, 0) + 1
|
||||
|
||||
print("New logo color counts:")
|
||||
for color, count in sorted(colors.items(), key=lambda x: x[1], reverse=True)[:15]:
|
||||
print(f"Color: {color}, count: {count}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspect_new_logo("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png")
|
||||
22
scratch/inspect_purple_logo.py
Normal file
22
scratch/inspect_purple_logo.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from PIL import Image
|
||||
|
||||
def inspect_purple_logo(path):
|
||||
img = Image.open(path)
|
||||
print("Size:", img.size)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
colors = {}
|
||||
for x in range(60, width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a > 0:
|
||||
color = (r, g, b, a)
|
||||
colors[color] = colors.get(color, 0) + 1
|
||||
|
||||
print("Non-transparent pixels in the text region (x >= 60):")
|
||||
for color, count in sorted(colors.items(), key=lambda x: x[1], reverse=True)[:10]:
|
||||
print(f"Color: {color}, count: {count}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspect_purple_logo("public/logo-purple.png")
|
||||
27
scratch/inspect_text_pixels.py
Normal file
27
scratch/inspect_text_pixels.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from PIL import Image
|
||||
|
||||
def inspect_text_pixels(path):
|
||||
img = Image.open(path)
|
||||
pixels = img.convert("RGBA").load()
|
||||
width, height = img.size
|
||||
|
||||
non_bg_coords = []
|
||||
|
||||
for x in range(150, width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
is_bg = (r >= 250 and g >= 250 and b >= 250)
|
||||
if not is_bg:
|
||||
non_bg_coords.append((x, y))
|
||||
|
||||
if non_bg_coords:
|
||||
xs = [p[0] for p in non_bg_coords]
|
||||
ys = [p[1] for p in non_bg_coords]
|
||||
print(f"Non-background bounding box on right:")
|
||||
print(f"X: {min(xs)} to {max(xs)} (width={max(xs) - min(xs) + 1})")
|
||||
print(f"Y: {min(ys)} to {max(ys)} (height={max(ys) - min(ys) + 1})")
|
||||
else:
|
||||
print("All pixels in the right region are background.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspect_text_pixels("/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png")
|
||||
32
scratch/process_logo.py
Normal file
32
scratch/process_logo.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import shutil
|
||||
from PIL import Image
|
||||
|
||||
def process_logo():
|
||||
src_path = "/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781942586218.png"
|
||||
|
||||
# 1. Copy original logo
|
||||
shutil.copy(src_path, "public/logo.png")
|
||||
shutil.copy(src_path, "public/images/logo.png")
|
||||
print("Copied original logo.png to public/ and public/images/")
|
||||
|
||||
# 2. Create purple version of the logo
|
||||
img = Image.open(src_path).convert("RGBA")
|
||||
pixels = img.load()
|
||||
width, height = img.size
|
||||
|
||||
# Target purple: RGB (102, 37, 130) -> Hex #662582
|
||||
# We will recolor all white/near-white pixels to purple, preserving their original alpha channel.
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a > 0:
|
||||
# If pixel is white or very close to white
|
||||
if r > 220 and g > 220 and b > 220:
|
||||
pixels[x, y] = (102, 37, 130, a)
|
||||
|
||||
img.save("public/logo-purple.png", "PNG")
|
||||
img.save("public/images/logo-purple.png", "PNG")
|
||||
print("Created logo-purple.png in public/ and public/images/")
|
||||
|
||||
if __name__ == "__main__":
|
||||
process_logo()
|
||||
64
scratch/recolor_scooter.py
Normal file
64
scratch/recolor_scooter.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import os
|
||||
from PIL import Image
|
||||
import colorsys
|
||||
|
||||
def recolor_yellow_to_purple(input_path, output_path):
|
||||
img = Image.open(input_path).convert("RGBA")
|
||||
width, height = img.size
|
||||
pixels = img.load()
|
||||
|
||||
# Target purple color in HSV
|
||||
# We want a vibrant purple matching --on-primary-container or --primary-container
|
||||
# Let's say hue is around 280 degrees (0.77 in 0-1 range)
|
||||
target_hue = 280.0 / 360.0
|
||||
|
||||
recolored_count = 0
|
||||
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
r, g, b, a = pixels[x, y]
|
||||
if a == 0:
|
||||
continue
|
||||
|
||||
# Convert RGB to HSV
|
||||
# RGB values are 0-255, colorsys expects 0-1
|
||||
h, s, v = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)
|
||||
|
||||
# Check if the pixel is yellow/orange
|
||||
# Yellow hue is around 40-75 degrees (0.11 to 0.21)
|
||||
# Orange/yellow can start around 35 degrees (0.097)
|
||||
# We want to avoid skin tones, which are typically warmer/redder (hue 10-30 degrees, i.e., 0.02 to 0.08)
|
||||
# and have lower saturation.
|
||||
# Bright yellow elements like the bag, scooter, shirt, helmet have high saturation (s > 0.4)
|
||||
# and high value (v > 0.4).
|
||||
|
||||
is_yellow = False
|
||||
|
||||
# Bright yellow/orange check
|
||||
# Hue range: 38 to 82 degrees (0.105 to 0.228)
|
||||
if 0.10 <= h <= 0.23 and s >= 0.35 and v >= 0.30:
|
||||
is_yellow = True
|
||||
# Let's also include slightly redder orange if it is highly saturated (which skin is not)
|
||||
elif 0.07 <= h < 0.10 and s >= 0.70 and v >= 0.50:
|
||||
is_yellow = True
|
||||
|
||||
if is_yellow:
|
||||
# We shift the hue to target purple (280 degrees)
|
||||
# Keep saturation and value similar, maybe boost saturation a bit for richness
|
||||
new_h = target_hue
|
||||
new_s = min(s * 1.0, 1.0)
|
||||
new_v = v
|
||||
|
||||
# Convert back to RGB
|
||||
new_r, new_g, new_b = colorsys.hsv_to_rgb(new_h, new_s, new_v)
|
||||
pixels[x, y] = (int(new_r * 255), int(new_g * 255), int(new_b * 255), a)
|
||||
recolored_count += 1
|
||||
|
||||
img.save(output_path, "PNG")
|
||||
print(f"Recolored {recolored_count} pixels and saved to {output_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
recolor_yellow_to_purple(
|
||||
"public/images/slider-courier-mask.png",
|
||||
"public/images/slider-courier-mask-purple.png"
|
||||
)
|
||||
81
scratch/remove_background.py
Normal file
81
scratch/remove_background.py
Normal file
@@ -0,0 +1,81 @@
|
||||
import collections
|
||||
from PIL import Image
|
||||
|
||||
def remove_background(image_path, output_path):
|
||||
# Load image and convert to RGBA
|
||||
img = Image.open(image_path).convert("RGBA")
|
||||
width, height = img.size
|
||||
pixels = img.load()
|
||||
|
||||
# Visited grid to prevent loops
|
||||
visited = [[False for _ in range(height)] for _ in range(width)]
|
||||
|
||||
# Queue for BFS
|
||||
queue = collections.deque()
|
||||
|
||||
# Helper to check if color matches checkerboard background
|
||||
def is_background_color(r, g, b):
|
||||
# White squares
|
||||
if r > 240 and g > 240 and b > 240:
|
||||
return True
|
||||
# Grey squares
|
||||
if 210 < r < 240 and 210 < g < 240 and 210 < b < 240:
|
||||
# Check if it's neutral grey
|
||||
if abs(r - g) < 5 and abs(g - b) < 5:
|
||||
return True
|
||||
return False
|
||||
|
||||
# Initialize queue with all border pixels
|
||||
for x in range(width):
|
||||
# Top border
|
||||
r, g, b, a = pixels[x, 0]
|
||||
if is_background_color(r, g, b):
|
||||
queue.append((x, 0))
|
||||
visited[x][0] = True
|
||||
|
||||
# Bottom border
|
||||
r, g, b, a = pixels[x, height - 1]
|
||||
if is_background_color(r, g, b):
|
||||
queue.append((x, height - 1))
|
||||
visited[x][height - 1] = True
|
||||
|
||||
for y in range(height):
|
||||
# Left border
|
||||
r, g, b, a = pixels[0, y]
|
||||
if is_background_color(r, g, b):
|
||||
queue.append((0, y))
|
||||
visited[0][y] = True
|
||||
|
||||
# Right border
|
||||
r, g, b, a = pixels[width - 1, y]
|
||||
if is_background_color(r, g, b):
|
||||
queue.append((width - 1, y))
|
||||
visited[width - 1][y] = True
|
||||
|
||||
# Perform BFS
|
||||
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
|
||||
while queue:
|
||||
cx, cy = queue.popleft()
|
||||
|
||||
# Set this background pixel to fully transparent
|
||||
pixels[cx, cy] = (0, 0, 0, 0)
|
||||
|
||||
# Check neighbors
|
||||
for dx, dy in directions:
|
||||
nx, ny = cx + dx, cy + dy
|
||||
if 0 <= nx < width and 0 <= ny < height:
|
||||
if not visited[nx][ny]:
|
||||
r, g, b, a = pixels[nx, ny]
|
||||
if is_background_color(r, g, b):
|
||||
visited[nx][ny] = True
|
||||
queue.append((nx, ny))
|
||||
|
||||
# Save the transparent image
|
||||
img.save(output_path, "PNG")
|
||||
print(f"Background successfully removed and saved to {output_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
remove_background(
|
||||
"public/images/slider-courier-mask-purple.png",
|
||||
"public/images/slider-courier-mask-purple.png"
|
||||
)
|
||||
127
scratch/update_brand_assets.py
Normal file
127
scratch/update_brand_assets.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import os
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
def update_brand_assets():
|
||||
new_logo_path = "/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png"
|
||||
rider_image_path = "public/images/slider-courier-mask-purple.png"
|
||||
|
||||
# 1. Load the new logo
|
||||
logo_img = Image.open(new_logo_path).convert("RGBA")
|
||||
|
||||
# 2. Crop the logo to the exact content area
|
||||
# Bounding box of the entire logo was:
|
||||
# X: 85 to 359 (width 275), Y: 40 to 83 (height 44)
|
||||
# Let's crop with a tiny padding: left=82, top=38, right=362, bottom=85
|
||||
cropped_logo = logo_img.crop((82, 38, 362, 85))
|
||||
cropped_w, cropped_h = cropped_logo.size
|
||||
|
||||
# 3. Create transparent purple logo (strip white/off-white background)
|
||||
transparent_purple = Image.new("RGBA", (cropped_w, cropped_h))
|
||||
pixels_purple = cropped_logo.load()
|
||||
pixels_tp = transparent_purple.load()
|
||||
|
||||
for x in range(cropped_w):
|
||||
for y in range(cropped_h):
|
||||
r, g, b, a = pixels_purple[x, y]
|
||||
# If the pixel is white or very close to white background (RGB > 248)
|
||||
if r >= 248 and g >= 248 and b >= 248:
|
||||
pixels_tp[x, y] = (0, 0, 0, 0)
|
||||
else:
|
||||
pixels_tp[x, y] = (r, g, b, a)
|
||||
|
||||
transparent_purple.save("public/logo-purple.png", "PNG")
|
||||
transparent_purple.save("public/images/logo-purple.png", "PNG")
|
||||
print("Saved logo-purple.png (transparent purple logo) to public/ and public/images/")
|
||||
|
||||
# 4. Create transparent white logo (convert all logo pixels to white, preserving alpha)
|
||||
transparent_white = Image.new("RGBA", (cropped_w, cropped_h))
|
||||
pixels_tw = transparent_white.load()
|
||||
|
||||
for x in range(cropped_w):
|
||||
for y in range(cropped_h):
|
||||
r, g, b, a = pixels_tp[x, y]
|
||||
if a > 0:
|
||||
pixels_tw[x, y] = (255, 255, 255, a)
|
||||
else:
|
||||
pixels_tw[x, y] = (0, 0, 0, 0)
|
||||
|
||||
transparent_white.save("public/logo.png", "PNG")
|
||||
transparent_white.save("public/images/logo.png", "PNG")
|
||||
print("Saved logo.png (transparent white logo) to public/ and public/images/")
|
||||
|
||||
# 5. Crop and create Favicon from the circle icon
|
||||
# Bounding box of the circle icon:
|
||||
# X: 85 to 149 (width 65), Y: 44 to 83 (height 40)
|
||||
# Let's crop from the original logo at (84, 43, 150, 84)
|
||||
icon_crop = logo_img.crop((84, 43, 150, 84))
|
||||
icon_w, icon_h = icon_crop.size
|
||||
|
||||
# Make background transparent
|
||||
transparent_icon = Image.new("RGBA", (icon_w, icon_h))
|
||||
pixels_ic = icon_crop.load()
|
||||
pixels_ti = transparent_icon.load()
|
||||
|
||||
for x in range(icon_w):
|
||||
for y in range(icon_h):
|
||||
r, g, b, a = pixels_ic[x, y]
|
||||
if r >= 248 and g >= 248 and b >= 248:
|
||||
pixels_ti[x, y] = (0, 0, 0, 0)
|
||||
else:
|
||||
pixels_ti[x, y] = (r, g, b, a)
|
||||
|
||||
# Resize to a square 32x32 and 48x48
|
||||
favicon_32 = transparent_icon.resize((32, 32), Image.Resampling.LANCZOS)
|
||||
favicon_48 = transparent_icon.resize((48, 48), Image.Resampling.LANCZOS)
|
||||
|
||||
# Save as ICO (favicon.ico)
|
||||
favicon_32.save("public/favicon.ico", format="ICO", sizes=[(32, 32), (48, 48)])
|
||||
|
||||
# Save as PNG icons
|
||||
favicon_48.save("public/favicon.png", "PNG")
|
||||
favicon_48.save("public/apple-icon.png", "PNG")
|
||||
print("Saved favicon.ico, favicon.png, and apple-icon.png to public/")
|
||||
|
||||
# 6. Erase old GOMOTO logo from the backpack bag and overlay white Nearle logo
|
||||
rider_img = Image.open(rider_image_path).convert("RGBA")
|
||||
rider_pixels = rider_img.load()
|
||||
|
||||
# Erase logo area X: 808 to 968, Y: 140 to 425 using linear interpolation between left (804) and right (970) columns
|
||||
left_x = 804
|
||||
right_x = 970
|
||||
|
||||
for y in range(140, 425):
|
||||
color_left = rider_pixels[left_x, y]
|
||||
color_right = rider_pixels[right_x, y]
|
||||
|
||||
width_logo = right_x - left_x - 1
|
||||
for x in range(left_x + 1, right_x):
|
||||
t = (x - left_x - 1) / width_logo
|
||||
r = int(color_left[0] * (1 - t) + color_right[0] * t)
|
||||
g = int(color_left[1] * (1 - t) + color_right[1] * t)
|
||||
b = int(color_left[2] * (1 - t) + color_right[2] * t)
|
||||
a = int(color_left[3] * (1 - t) + color_right[3] * t)
|
||||
rider_pixels[x, y] = (r, g, b, a)
|
||||
|
||||
print("Erased old GOMOTO logo from delivery bag.")
|
||||
|
||||
# Prepare white Nearle logo to be pasted onto the bag
|
||||
# Let's resize the white Nearle logo
|
||||
# The GOMOTO text was centered. Let's make our Nearle logo width = 120, height = 20
|
||||
bag_logo_w = 120
|
||||
bag_logo_h = 20
|
||||
resized_bag_logo = transparent_white.resize((bag_logo_w, bag_logo_h), Image.Resampling.LANCZOS)
|
||||
|
||||
# Center on the bag at x = 887 - (120/2) = 827, y = 284 - (20/2) = 274
|
||||
# Let's adjust slightly for visual balance
|
||||
paste_x = 827
|
||||
paste_y = 265
|
||||
|
||||
# Paste the logo with transparency mask
|
||||
rider_img.paste(resized_bag_logo, (paste_x, paste_y), resized_bag_logo)
|
||||
|
||||
# Save the updated rider image
|
||||
rider_img.save(rider_image_path, "PNG")
|
||||
print("Successfully overlaid white Nearle logo on rider's backpack and saved.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_brand_assets()
|
||||
151
scratch/update_brand_assets_v3.py
Normal file
151
scratch/update_brand_assets_v3.py
Normal file
@@ -0,0 +1,151 @@
|
||||
import os
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
def update_brand_assets_v3():
|
||||
new_logo_path = "/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png"
|
||||
# Base rider image: we load from the original to ensure clean edit
|
||||
rider_image_base = "public/images/slider-courier-mask.png"
|
||||
# We will output to v3
|
||||
rider_image_out = "public/images/slider-courier-mask-purple-v3.png"
|
||||
|
||||
# 1. Load the new logo
|
||||
logo_img = Image.open(new_logo_path).convert("RGBA")
|
||||
|
||||
# 2. Crop the logo to the exact content area
|
||||
cropped_logo = logo_img.crop((82, 38, 362, 85))
|
||||
cropped_w, cropped_h = cropped_logo.size
|
||||
|
||||
# 3. Create transparent purple logo (strip white/off-white background)
|
||||
transparent_purple = Image.new("RGBA", (cropped_w, cropped_h))
|
||||
pixels_purple = cropped_logo.load()
|
||||
pixels_tp = transparent_purple.load()
|
||||
|
||||
for x in range(cropped_w):
|
||||
for y in range(cropped_h):
|
||||
r, g, b, a = pixels_purple[x, y]
|
||||
if r >= 248 and g >= 248 and b >= 248:
|
||||
pixels_tp[x, y] = (0, 0, 0, 0)
|
||||
else:
|
||||
pixels_tp[x, y] = (r, g, b, a)
|
||||
|
||||
transparent_purple.save("public/logo-purple.png", "PNG")
|
||||
transparent_purple.save("public/images/logo-purple.png", "PNG")
|
||||
|
||||
# 4. Create transparent white logo (convert all logo pixels to white, preserving alpha)
|
||||
transparent_white = Image.new("RGBA", (cropped_w, cropped_h))
|
||||
pixels_tw = transparent_white.load()
|
||||
|
||||
for x in range(cropped_w):
|
||||
for y in range(cropped_h):
|
||||
r, g, b, a = pixels_tp[x, y]
|
||||
if a > 0:
|
||||
pixels_tw[x, y] = (255, 255, 255, a)
|
||||
else:
|
||||
pixels_tw[x, y] = (0, 0, 0, 0)
|
||||
|
||||
transparent_white.save("public/logo.png", "PNG")
|
||||
transparent_white.save("public/images/logo.png", "PNG")
|
||||
|
||||
# 5. Crop and create Favicon from the circle icon
|
||||
icon_crop = logo_img.crop((84, 43, 150, 84))
|
||||
icon_w, icon_h = icon_crop.size
|
||||
|
||||
transparent_icon = Image.new("RGBA", (icon_w, icon_h))
|
||||
pixels_ic = icon_crop.load()
|
||||
pixels_ti = transparent_icon.load()
|
||||
|
||||
for x in range(icon_w):
|
||||
for y in range(icon_h):
|
||||
r, g, b, a = pixels_ic[x, y]
|
||||
if r >= 248 and g >= 248 and b >= 248:
|
||||
pixels_ti[x, y] = (0, 0, 0, 0)
|
||||
else:
|
||||
pixels_ti[x, y] = (r, g, b, a)
|
||||
|
||||
favicon_32 = transparent_icon.resize((32, 32), Image.Resampling.LANCZOS)
|
||||
favicon_48 = transparent_icon.resize((48, 48), Image.Resampling.LANCZOS)
|
||||
favicon_32.save("public/favicon.ico", format="ICO", sizes=[(32, 32), (48, 48)])
|
||||
favicon_48.save("public/favicon.png", "PNG")
|
||||
favicon_48.save("public/apple-icon.png", "PNG")
|
||||
|
||||
# 6. Load base yellow rider, recolor yellow to purple (recolor scooter panels, helmet, shirt, bag)
|
||||
# We do a fresh recolor to make sure we don't have residual artifacts
|
||||
import colorsys
|
||||
img_rider = Image.open(rider_image_base).convert("RGBA")
|
||||
pixels_rider = img_rider.load()
|
||||
width_rider, height_rider = img_rider.size
|
||||
|
||||
target_hue = 280.0 / 360.0
|
||||
|
||||
for x in range(width_rider):
|
||||
for y in range(height_rider):
|
||||
r, g, b, a = pixels_rider[x, y]
|
||||
if a == 0:
|
||||
continue
|
||||
h, s, v = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)
|
||||
is_yellow = False
|
||||
if 0.10 <= h <= 0.23 and s >= 0.35 and v >= 0.30:
|
||||
is_yellow = True
|
||||
elif 0.07 <= h < 0.10 and s >= 0.70 and v >= 0.50:
|
||||
is_yellow = True
|
||||
|
||||
if is_yellow:
|
||||
new_h = target_hue
|
||||
new_s = min(s * 1.0, 1.0)
|
||||
new_v = v
|
||||
new_r, new_g, new_b = colorsys.hsv_to_rgb(new_h, new_s, new_v)
|
||||
pixels_rider[x, y] = (int(new_r * 255), int(new_g * 255), int(new_b * 255), a)
|
||||
|
||||
# 7. Erase old GOMOTO logo using linear interpolation
|
||||
left_x = 804
|
||||
right_x = 970
|
||||
|
||||
for y in range(140, 425):
|
||||
color_left = pixels_rider[left_x, y]
|
||||
color_right = pixels_rider[right_x, y]
|
||||
width_logo = right_x - left_x - 1
|
||||
for x in range(left_x + 1, right_x):
|
||||
t = (x - left_x - 1) / width_logo
|
||||
r = int(color_left[0] * (1 - t) + color_right[0] * t)
|
||||
g = int(color_left[1] * (1 - t) + color_right[1] * t)
|
||||
b = int(color_left[2] * (1 - t) + color_right[2] * t)
|
||||
a = int(color_left[3] * (1 - t) + color_right[3] * t)
|
||||
pixels_rider[x, y] = (r, g, b, a)
|
||||
|
||||
# 8. Create a premium black badge (rounded rectangle)
|
||||
# Center on the bag at x = 887, y = 275
|
||||
# Width = 144, Height = 36 (radius = 8)
|
||||
badge_w = 148
|
||||
badge_h = 38
|
||||
badge_left = 887 - (badge_w // 2)
|
||||
badge_top = 270 - (badge_h // 2)
|
||||
badge_right = badge_left + badge_w
|
||||
badge_bottom = badge_top + badge_h
|
||||
|
||||
draw = ImageDraw.Draw(img_rider)
|
||||
# Draw dark premium badge: pure black with full opacity (#0b010f or #000000)
|
||||
# A tiny bit of rounding gives it a sleek rubber-badge look
|
||||
draw.rounded_rectangle(
|
||||
[badge_left, badge_top, badge_right, badge_bottom],
|
||||
radius=8,
|
||||
fill=(18, 2, 23, 255) # matches --brand-dark color perfectly!
|
||||
)
|
||||
|
||||
# 9. Resize and draw white Nearle logo inside the badge
|
||||
# Logo size inside the badge: width = 120, height = 20
|
||||
logo_w = 120
|
||||
logo_h = 20
|
||||
resized_white_logo = transparent_white.resize((logo_w, logo_h), Image.Resampling.LANCZOS)
|
||||
|
||||
logo_left = 887 - (logo_w // 2)
|
||||
logo_top = 270 - (logo_h // 2)
|
||||
|
||||
# Paste logo on top of the black badge
|
||||
img_rider.paste(resized_white_logo, (logo_left, logo_top), resized_white_logo)
|
||||
|
||||
# Save output
|
||||
img_rider.save(rider_image_out, "PNG")
|
||||
print(f"Created updated rider image with black badge at {rider_image_out}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_brand_assets_v3()
|
||||
61
scratch/update_favicon_v4.py
Normal file
61
scratch/update_favicon_v4.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
def update_favicon_v4():
|
||||
logo_path = "/Users/apple/.gemini/antigravity-ide/brain/822556bd-47a7-4c07-8975-803618af0a3a/media__1781946188768.png"
|
||||
|
||||
# 1. Load original logo
|
||||
logo_img = Image.open(logo_path).convert("RGBA")
|
||||
|
||||
# 2. Crop the circle icon: X: 85 to 149 (width=65), Y: 44 to 83 (height=40)
|
||||
icon_w = 65
|
||||
icon_h = 40
|
||||
icon_crop = logo_img.crop((85, 44, 150, 84))
|
||||
|
||||
# 3. Strip any white background from the cropped icon
|
||||
icon_tp = Image.new("RGBA", (icon_w, icon_h))
|
||||
pixels_ic = icon_crop.load()
|
||||
pixels_tp = icon_tp.load()
|
||||
for x in range(icon_w):
|
||||
for y in range(icon_h):
|
||||
r, g, b, a = pixels_ic[x, y]
|
||||
if r >= 248 and g >= 248 and b >= 248:
|
||||
pixels_tp[x, y] = (0, 0, 0, 0)
|
||||
else:
|
||||
pixels_tp[x, y] = (r, g, b, a)
|
||||
|
||||
# 4. Place it inside a square 65x65 box to prevent squishing
|
||||
square_size = 65
|
||||
square_icon = Image.new("RGBA", (square_size, square_size), (0, 0, 0, 0))
|
||||
y_offset = (square_size - icon_h) // 2
|
||||
square_icon.paste(icon_tp, (0, y_offset), icon_tp)
|
||||
|
||||
# 5. Draw a solid white circle background behind the square icon
|
||||
favicon_img = Image.new("RGBA", (square_size, square_size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(favicon_img)
|
||||
|
||||
# Draw solid white circle (leave a small transparent margin around it for clean rendering)
|
||||
margin = 2
|
||||
draw.ellipse(
|
||||
[margin, margin, square_size - margin, square_size - margin],
|
||||
fill=(255, 255, 255, 255)
|
||||
)
|
||||
|
||||
# Paste the purple logo on top of the white circle
|
||||
favicon_img.paste(square_icon, (0, 0), square_icon)
|
||||
|
||||
# 6. Resize to standard sizes and save
|
||||
favicon_32 = favicon_img.resize((32, 32), Image.Resampling.LANCZOS)
|
||||
favicon_48 = favicon_img.resize((48, 48), Image.Resampling.LANCZOS)
|
||||
|
||||
# Save favicon.ico to public/ and src/app/
|
||||
favicon_32.save("public/favicon.ico", format="ICO", sizes=[(32, 32), (48, 48)])
|
||||
favicon_32.save("src/app/favicon.ico", format="ICO", sizes=[(32, 32), (48, 48)])
|
||||
|
||||
# Save PNG versions
|
||||
favicon_48.save("public/favicon.png", "PNG")
|
||||
favicon_48.save("public/apple-icon.png", "PNG")
|
||||
|
||||
print("Successfully generated non-squished favicon with solid white circle background!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_favicon_v4()
|
||||
Reference in New Issue
Block a user