Created
December 20, 2025 15:36
-
-
Save lambdalisue/0c3c42901d8ed3cda58b3988ea6c984a to your computer and use it in GitHub Desktop.
Add transparent padding to an icon for macOS Tahoe compatibility
This file contains hidden or 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
| #!/usr/bin/env python3 | |
| """ | |
| Add transparent padding to an icon for macOS Tahoe compatibility. | |
| macOS Tahoe automatically adds white borders to icons that extend to the edge. | |
| This script adds transparent padding around the icon to prevent this behavior. | |
| Usage: | |
| python3 add-icon-padding.py input.png output.png [--padding 12] | |
| Arguments: | |
| input.png - Source icon file | |
| output.png - Output icon file with padding | |
| --padding - Padding percentage (default: 12%) | |
| """ | |
| import sys | |
| from PIL import Image | |
| import argparse | |
| def add_padding(input_path: str, output_path: str, padding_percent: int = 12): | |
| """ | |
| Add transparent padding around an icon. | |
| Args: | |
| input_path: Path to input PNG file | |
| output_path: Path to output PNG file | |
| padding_percent: Percentage of padding to add (default 12%) | |
| """ | |
| # Open the original icon | |
| img = Image.open(input_path) | |
| # Ensure RGBA mode for transparency | |
| if img.mode != 'RGBA': | |
| img = img.convert('RGBA') | |
| # Get original dimensions | |
| orig_width, orig_height = img.size | |
| print(f"π Original size: {orig_width}x{orig_height}") | |
| # Calculate new dimensions with padding | |
| # padding_percent on each side, so total increase is 2 * padding_percent | |
| scale_factor = 1 + (2 * padding_percent / 100) | |
| new_width = int(orig_width * scale_factor) | |
| new_height = int(orig_height * scale_factor) | |
| print(f"π New size with {padding_percent}% padding: {new_width}x{new_height}") | |
| # Create new transparent canvas | |
| new_img = Image.new('RGBA', (new_width, new_height), (0, 0, 0, 0)) | |
| # Calculate position to center the original icon | |
| x_offset = (new_width - orig_width) // 2 | |
| y_offset = (new_height - orig_height) // 2 | |
| print(f"π Centering icon with offset: ({x_offset}, {y_offset})") | |
| # Paste the original icon onto the new canvas | |
| new_img.paste(img, (x_offset, y_offset), img) | |
| # Save the result | |
| new_img.save(output_path, 'PNG') | |
| print(f"β Saved padded icon to: {output_path}") | |
| def create_iconset(source_png: str, iconset_dir: str, padding_percent: int = 12): | |
| """ | |
| Create a complete .iconset directory with all required sizes. | |
| Args: | |
| source_png: Path to source PNG (should be large, ideally 1024x1024 or larger) | |
| iconset_dir: Path to .iconset directory to create | |
| padding_percent: Padding percentage | |
| """ | |
| import os | |
| # Icon sizes required for macOS | |
| sizes = [16, 32, 64, 128, 256, 512, 1024] | |
| # Create iconset directory | |
| os.makedirs(iconset_dir, exist_ok=True) | |
| print(f"π Creating iconset at: {iconset_dir}") | |
| # Load source image | |
| source_img = Image.open(source_png) | |
| if source_img.mode != 'RGBA': | |
| source_img = source_img.convert('RGBA') | |
| # Calculate padding | |
| scale_factor = 1 + (2 * padding_percent / 100) | |
| for size in sizes: | |
| # Calculate padded size | |
| padded_size = int(size * scale_factor) | |
| # Resize source image to target padded size | |
| resized = source_img.resize((padded_size, padded_size), Image.Resampling.LANCZOS) | |
| # Create canvas for the final size (without padding in filename) | |
| canvas = Image.new('RGBA', (size, size), (0, 0, 0, 0)) | |
| # Resize to actual size (this maintains the padding ratio) | |
| final = resized.resize((size, size), Image.Resampling.LANCZOS) | |
| # Save 1x version | |
| output_path = os.path.join(iconset_dir, f"icon_{size}x{size}.png") | |
| final.save(output_path, 'PNG') | |
| print(f" β Created {size}x{size}") | |
| # Save 2x version | |
| size_2x = size * 2 | |
| final_2x = resized.resize((size_2x, size_2x), Image.Resampling.LANCZOS) | |
| output_path_2x = os.path.join(iconset_dir, f"icon_{size}x{size}@2x.png") | |
| final_2x.save(output_path_2x, 'PNG') | |
| print(f" β Created {size}x{size}@2x") | |
| print(f"\nβ Iconset created successfully!") | |
| print(f"Now run: iconutil -c icns {iconset_dir}") | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description="Add transparent padding to icons for macOS Sequoia" | |
| ) | |
| parser.add_argument("input", help="Input PNG file") | |
| parser.add_argument("output", nargs='?', help="Output PNG file (optional if --iconset is used)") | |
| parser.add_argument("--padding", type=int, default=12, help="Padding percentage (default: 12)") | |
| parser.add_argument("--iconset", help="Create a complete .iconset directory") | |
| args = parser.parse_args() | |
| # Check if PIL is available | |
| try: | |
| from PIL import Image | |
| except ImportError: | |
| print("β Error: Pillow library is required") | |
| print("Install it with: pip3 install Pillow") | |
| sys.exit(1) | |
| if args.iconset: | |
| # Create iconset mode | |
| create_iconset(args.input, args.iconset, args.padding) | |
| elif args.output: | |
| # Single image mode | |
| add_padding(args.input, args.output, args.padding) | |
| else: | |
| parser.error("Either output file or --iconset must be specified") | |
| if __name__ == "__main__": | |
| main() |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://lapcatsoftware.com/articles/2025/6/2.html
https://9to5mac.com/2025/08/08/macos-tahoe-fix-gray-box-icons/
XcodesOrg/XcodesApp#721
https://mjtsai.com/blog/2025/10/02/how-to-export-a-mac-icon-file-with-the-proper-margins/