11import base64
22import io
3- from PIL import Image , ImageDraw
3+ from PIL import Image
44
5- # 1. Load source images
65logo_black = Image .open ('public/ClientEcho_logo.png' ).convert ('RGBA' )
76logo_white = Image .open ('public/ClientEcho_logo_white.png' ).convert ('RGBA' )
87w , h = logo_black .size
98
10- # 2. Build High-DPI Obsidian Squircle Icons (Optimized for Google Search 48x48 multiples, Chrome, & Apple Touch)
11- def create_squircle_favicon (size , output_path ):
12- scale = 4
13- hr_size = size * scale
14- bg = Image .new ('RGBA' , (hr_size , hr_size ), (0 , 0 , 0 , 0 ))
15- draw = ImageDraw .Draw (bg )
16- radius = int (hr_size * 0.225 )
17-
18- # Modern dark obsidian tile (#111116)
19- draw .rounded_rectangle ([(0 , 0 ), (hr_size - 1 , hr_size - 1 )], radius = radius , fill = (17 , 17 , 22 , 255 ))
20-
21- # White logo glyph with ~15% optical margin
22- glyph_size = int (hr_size * 0.70 )
23- glyph = logo_white .resize ((glyph_size , glyph_size ), Image .Resampling .LANCZOS )
24- offset = (hr_size - glyph_size ) // 2
25- bg .paste (glyph , (offset , offset ), glyph )
26-
27- final_img = bg .resize ((size , size ), Image .Resampling .LANCZOS )
28- final_img .save (output_path , 'PNG' , optimize = True )
29- print (f'Created { output_path } ({ size } x{ size } )' )
30- return final_img
31-
32- # Google Search multiples of 48px + standard web sizes
33- create_squircle_favicon (48 , 'public/favicon-48x48.png' )
34- create_squircle_favicon (96 , 'public/favicon-96x96.png' )
35- create_squircle_favicon (144 , 'public/favicon-144x144.png' )
36- create_squircle_favicon (192 , 'public/favicon-192x192.png' )
37- create_squircle_favicon (512 , 'public/favicon-512x512.png' )
38- ico_source = create_squircle_favicon (180 , 'public/apple-touch-icon.png' )
39-
40- # Generate multi-resolution .ico for Googlebot & standard browser root
41- ico_source .save ('public/favicon.ico' , format = 'ICO' , sizes = [(16 , 16 ), (32 , 32 ), (48 , 48 )])
42- print ('Created public/favicon.ico (16/32/48)' )
43-
44- # 3. Create Adaptive SVG favicon for modern browsers
459buf_black = io .BytesIO ()
4610logo_black .save (buf_black , format = 'PNG' )
4711b64_black = base64 .b64encode (buf_black .getvalue ()).decode ('utf-8' )
@@ -50,6 +14,7 @@ def create_squircle_favicon(size, output_path):
5014logo_white .save (buf_white , format = 'PNG' )
5115b64_white = base64 .b64encode (buf_white .getvalue ()).decode ('utf-8' )
5216
17+ # Fully transparent background, dynamic adaptive color switching
5318svg_content = f'''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 { w } { h } " width="{ w } " height="{ h } ">
5419 <style>
5520 .icon-light {{ display: block; }}
@@ -65,4 +30,4 @@ def create_squircle_favicon(size, output_path):
6530
6631with open ('public/favicon.svg' , 'w' , encoding = 'utf-8' ) as f :
6732 f .write (svg_content )
68- print ('Created public/favicon.svg (Adaptive SVG )' )
33+ print ('Successfully generated adaptive public/favicon.svg (100% transparent, auto switches Black on Light / White on Dark )' )
0 commit comments