|
| 1 | +import os |
| 2 | +from PIL import Image, ImageChops |
| 3 | + |
| 4 | +def process_custom_logo(): |
| 5 | + source_path = r"C:\Users\PMLS\AppData\Roaming\Chat\input_file_0.png" |
| 6 | + # Fallback to the media path if direct input path doesn't work (environment specific) |
| 7 | + media_path = r"C:\Users\PMLS\.gemini\antigravity\brain\44926c08-11b7-45e9-bbec-fb534a051b01\media__1772557467154.jpg" |
| 8 | + |
| 9 | + if os.path.exists(media_path): |
| 10 | + source_path = media_path |
| 11 | + elif not os.path.exists(source_path): |
| 12 | + print("Error: Source image not found.") |
| 13 | + return |
| 14 | + |
| 15 | + img = Image.open(source_path).convert("RGB") |
| 16 | + width, height = img.size |
| 17 | + |
| 18 | + # Simple bounding box detection: |
| 19 | + # We find where the color differs from the corner (background) |
| 20 | + bg_color = img.getpixel((0, 0)) |
| 21 | + diff = ImageChops.difference(img, Image.new("RGB", img.size, bg_color)) |
| 22 | + bbox = diff.getbbox() |
| 23 | + |
| 24 | + if not bbox: |
| 25 | + print("Error: Could not determine bounding box of the logo.") |
| 26 | + # Fallback to middle crop if it fails |
| 27 | + left, top, right, bottom = width//4, height//4, 3*width//4, 3*height//4 |
| 28 | + else: |
| 29 | + # Give it a tiny bit of padding or just use the bbox |
| 30 | + left, top, right, bottom = bbox |
| 31 | + |
| 32 | + # Make it a square if it's not |
| 33 | + w, h = right - left, bottom - top |
| 34 | + side = max(w, h) |
| 35 | + center_x, center_y = (left + right)/2, (top + bottom)/2 |
| 36 | + |
| 37 | + new_left = max(0, center_x - side/2) |
| 38 | + new_top = max(0, center_y - side/2) |
| 39 | + new_right = min(width, center_x + side/2) |
| 40 | + new_bottom = min(height, center_y + side/2) |
| 41 | + |
| 42 | + logo = img.crop((new_left, new_top, new_right, new_bottom)) |
| 43 | + |
| 44 | + target_dir = os.path.join("assets", "favicon") |
| 45 | + os.makedirs(target_dir, exist_ok=True) |
| 46 | + |
| 47 | + resample = Image.Resampling.LANCZOS |
| 48 | + |
| 49 | + logo.resize((512, 512), resample).save(os.path.join(target_dir, "android-chrome-512x512.png")) |
| 50 | + logo.resize((192, 192), resample).save(os.path.join(target_dir, "android-chrome-192x192.png")) |
| 51 | + logo.resize((180, 180), resample).save(os.path.join(target_dir, "apple-touch-icon.png")) |
| 52 | + logo.resize((32, 32), resample).save(os.path.join(target_dir, "favicon-32x32.png")) |
| 53 | + |
| 54 | + # For small sizes, we might want to keep some sharpening/contrast |
| 55 | + logo16 = logo.resize((16, 16), resample) |
| 56 | + logo16.save(os.path.join(target_dir, "favicon-16x16.png")) |
| 57 | + |
| 58 | + # ICO |
| 59 | + logo48 = logo.resize((48, 48), resample) |
| 60 | + logo32 = logo.resize((32, 32), resample) |
| 61 | + logo.save(os.path.join(target_dir, "favicon.ico"), format='ICO', sizes=[(16, 16), (32, 32), (48, 48)], append_images=[logo32, logo48]) |
| 62 | + |
| 63 | + print("Custom logo favicon generated successfully.") |
| 64 | + |
| 65 | +def update_html(): |
| 66 | + import re |
| 67 | + print("Updating HTML files to v8...") |
| 68 | + for root, dirs, files in os.walk("."): |
| 69 | + if any(x in root for x in ['.git', 'node_modules', '.gemini']): continue |
| 70 | + for name in files: |
| 71 | + if name.endswith(".html"): |
| 72 | + path = os.path.join(root, name) |
| 73 | + with open(path, 'r', encoding='utf-8') as f: |
| 74 | + content = f.read() |
| 75 | + |
| 76 | + # Update cache buster to v8 |
| 77 | + if "favicon.ico?v=" in content: |
| 78 | + content = re.sub(r'favicon\.ico\?v=\d+', 'favicon.ico?v=8', content) |
| 79 | + |
| 80 | + with open(path, 'w', encoding='utf-8') as f: |
| 81 | + f.write(content) |
| 82 | + print("HTML updated.") |
| 83 | + |
| 84 | +if __name__ == "__main__": |
| 85 | + process_custom_logo() |
| 86 | + update_html() |
0 commit comments