From c29eefe030ae79dbcb716ae8b6d02fc6cc027881 Mon Sep 17 00:00:00 2001 From: Keith Smith Date: Sat, 6 Dec 2025 09:22:41 -0700 Subject: [PATCH] Add application icon for all platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created icon generation script (create_icon.py) - Generated PNG icon (512x512) with word search grid design - Generated ICO file for Windows (multi-resolution) - Updated PyInstaller spec to use platform-appropriate icons - Updated .gitignore to exclude generated icon size variants Icon features: - Light blue gradient background - 5x5 grid with letters spelling WORD, SEARCH, etc. - Highlighted "WORD" in green to show found word - Professional, clean design Windows: icon.ico macOS: icon.icns (generate on macOS with provided commands) Linux: icon.png 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .gitignore | 6 ++ create_icon.py | 145 +++++++++++++++++++++++++++++++++++++++++++++++ icon.ico | Bin 0 -> 565 bytes icon.png | Bin 0 -> 6949 bytes word_search.spec | 14 ++++- 5 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 create_icon.py create mode 100644 icon.ico create mode 100644 icon.png diff --git a/.gitignore b/.gitignore index 64ed49f..9369c81 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,9 @@ Thumbs.db # Generated PDF files (optional - uncomment if you don't want to track PDFs) # *.pdf + +# Generated icon files (sizes) +icon_*.png + +# macOS icon set directory +icon.iconset/ diff --git a/create_icon.py b/create_icon.py new file mode 100644 index 0000000..a2aa7de --- /dev/null +++ b/create_icon.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +""" +Script to create the Word Search application icon. +Creates a PNG icon that can be converted to ICO/ICNS for different platforms. +""" + +from PIL import Image, ImageDraw, ImageFont +import os + +def create_icon(): + # Icon sizes to generate + sizes = [16, 32, 48, 64, 128, 256, 512] + + # Create the largest size first + size = 512 + img = Image.new('RGB', (size, size), color='white') + draw = ImageDraw.Draw(img) + + # Draw background gradient (light blue to white) + for y in range(size): + # Gradient from light blue to white + blue_value = int(220 + (35 * y / size)) + color = (blue_value, blue_value, 255) + draw.line([(0, y), (size, y)], fill=color) + + # Draw a grid pattern (simplified word search grid) + grid_size = 5 + cell_size = size // (grid_size + 2) + margin = cell_size + + # Draw grid lines + for i in range(grid_size + 1): + x = margin + i * cell_size + y = margin + i * cell_size + # Vertical lines + draw.line([(x, margin), (x, margin + grid_size * cell_size)], + fill=(100, 100, 150), width=3) + # Horizontal lines + draw.line([(margin, y), (margin + grid_size * cell_size, y)], + fill=(100, 100, 150), width=3) + + # Add some letters to make it look like a word search + letters = [ + ['W', 'O', 'R', 'D', 'S'], + ['X', 'S', 'E', 'A', 'R'], + ['P', 'U', 'Z', 'Z', 'L'], + ['G', 'A', 'M', 'E', 'F'], + ['F', 'I', 'N', 'D', 'X'] + ] + + # Try to use a bold font, fallback to default + try: + # Try common font paths + font_size = cell_size // 2 + font_paths = [ + '/usr/share/fonts/liberation/LiberationSans-Bold.ttf', + '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', + '/System/Library/Fonts/Helvetica.ttc', + 'C:\\Windows\\Fonts\\arialbd.ttf' + ] + font = None + for path in font_paths: + if os.path.exists(path): + font = ImageFont.truetype(path, font_size) + break + if font is None: + font = ImageFont.load_default() + except: + font = ImageFont.load_default() + + # Draw letters + for i in range(grid_size): + for j in range(grid_size): + letter = letters[i][j] + x = margin + j * cell_size + cell_size // 2 + y = margin + i * cell_size + cell_size // 2 + + # Get text bounding box for centering + bbox = draw.textbbox((0, 0), letter, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + draw.text((x - text_width // 2, y - text_height // 2), + letter, fill=(50, 50, 100), font=font) + + # Highlight "WORD" in the first row with a green overlay + highlight_color = (100, 255, 100, 100) # Light green with transparency + overlay = Image.new('RGBA', (size, size), (255, 255, 255, 0)) + overlay_draw = ImageDraw.Draw(overlay) + + # Draw highlight rectangle for "WORD" + x1 = margin + 5 + y1 = margin + 5 + x2 = margin + 4 * cell_size - 5 + y2 = margin + cell_size - 5 + overlay_draw.rounded_rectangle([x1, y1, x2, y2], radius=10, + fill=highlight_color, outline=(50, 200, 50, 200), width=3) + + # Convert to RGBA and composite with overlay + img = img.convert('RGBA') + img = Image.alpha_composite(img, overlay) + + # Save main PNG icon + img.save('icon.png', 'PNG') + print("Created: icon.png (512x512)") + + # Create smaller sizes + for new_size in sizes: + if new_size < 512: + resized = img.resize((new_size, new_size), Image.Resampling.LANCZOS) + resized.save(f'icon_{new_size}.png', 'PNG') + print(f"Created: icon_{new_size}.png") + + # Create ICO file for Windows (contains multiple sizes) + try: + icon_sizes = [(16, 16), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)] + images = [] + for icon_size in icon_sizes: + resized = img.resize(icon_size, Image.Resampling.LANCZOS) + images.append(resized) + + images[0].save('icon.ico', format='ICO', sizes=icon_sizes, append_images=images[1:]) + print("Created: icon.ico (multi-resolution)") + except Exception as e: + print(f"Note: Could not create ICO file: {e}") + + # Create ICNS for macOS (requires pillow with ICNS support or iconutil) + print("\nFor macOS .icns file, use the following command on macOS:") + print(" mkdir icon.iconset") + print(" sips -z 16 16 icon.png --out icon.iconset/icon_16x16.png") + print(" sips -z 32 32 icon.png --out icon.iconset/icon_16x16@2x.png") + print(" sips -z 32 32 icon.png --out icon.iconset/icon_32x32.png") + print(" sips -z 64 64 icon.png --out icon.iconset/icon_32x32@2x.png") + print(" sips -z 128 128 icon.png --out icon.iconset/icon_128x128.png") + print(" sips -z 256 256 icon.png --out icon.iconset/icon_128x128@2x.png") + print(" sips -z 256 256 icon.png --out icon.iconset/icon_256x256.png") + print(" sips -z 512 512 icon.png --out icon.iconset/icon_256x256@2x.png") + print(" sips -z 512 512 icon.png --out icon.iconset/icon_512x512.png") + print(" iconutil -c icns icon.iconset") + print(" rm -rf icon.iconset") + + print("\nIcon creation complete!") + +if __name__ == '__main__': + create_icon() diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..918a10c5bfc1afff0c2518abdb97fe3894817336 GIT binary patch literal 565 zcmV-50?PdW0096201yxW0000W03QMX02TlM0EtjeM-2)Z3IG5A4M|8uQUCw|5C8xG z5C{eU001BJ|6u?C0p>|WK~#90g_Fr{+%OD=KT?v%TjHiD8uXO+f20=31GFg6q_bJp z!XE6IWO6A1L0rUNT;=)M48Q;cFuO3@eIY|`cx-|x6sxETve~^V zh{2EJcaH4~H9}|{X(>3jqStDOGamNecMth_Yh-5wQ@Mjs2ay(q-oX~EKA0$a5$V%t;CqPyW73B(F}%R$24`Q zD$~@_G!E|_BEqs{`o2L`n5GWr&WOBgqxV87nf?C6JTIt1j0@hswb86>HY4YP_v;`@ zN@gPKyw_@o$Ti2CT{5mVRY6r&T`B82e{}dCtzPgCQYiW@H76rV00000NkvXXu0mjf D24ehV literal 0 HcmV?d00001 diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5d5310ef310486edf99af25f4650479d0f82b3 GIT binary patch literal 6949 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