summaryrefslogtreecommitdiffstats
path: root/deluge/scripts/create_icons.py
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/scripts/create_icons.py')
-rwxr-xr-xdeluge/scripts/create_icons.py201
1 files changed, 201 insertions, 0 deletions
diff --git a/deluge/scripts/create_icons.py b/deluge/scripts/create_icons.py
new file mode 100755
index 0000000..479505c
--- /dev/null
+++ b/deluge/scripts/create_icons.py
@@ -0,0 +1,201 @@
+#!/usr/bin/python3
+#
+# Create Deluge PNG icons from SVG
+#
+# Required image tools:
+# * rsvg-convert
+# * convert (ImageMagik)
+# * oxipng
+# * pngquant
+#
+import shutil
+import subprocess
+from dataclasses import dataclass, field
+from pathlib import Path
+
+
+@dataclass
+class IconPack:
+ name: str
+ dir: Path
+ icon_sizes: list[int]
+ panel_sizes: list[int]
+ ico_sizes: list[int]
+ pixmaps_dir: Path = field(init=False)
+ theme_dir: Path = field(init=False)
+ theme_svg: Path = field(init=False)
+ theme_pngs: dict[int, Path] = field(init=False)
+ logo_svg: Path = field(init=False)
+ logo_ico: Path = field(init=False)
+ logo_png: Path = field(init=False)
+
+ def __post_init__(self):
+ self.pixmaps_dir = self.dir / 'pixmaps'
+ self.logo_svg = self.pixmaps_dir / f'{self.name}.svg'
+ self.logo_ico = self.pixmaps_dir / f'{self.name}.ico'
+ self.logo_png = self.pixmaps_dir / f'{self.name}.png'
+
+ self.theme_dir = self.dir / 'icons' / 'hicolor'
+ self.theme_svg = self.theme_dir / 'scalable' / 'apps' / f'{self.name}.svg'
+ self.theme_pngs = self.create_theme_pngs_paths(
+ self.name, self.icon_sizes, self.theme_dir
+ )
+
+ @staticmethod
+ def create_theme_pngs_paths(name, icon_sizes, out_dir):
+ return {
+ size: out_dir / f'{size}x{size}' / 'apps' / f'{name}.png'
+ for size in icon_sizes
+ }
+
+
+@dataclass
+class WebIconPack:
+ name: str
+ dir: Path
+ icon_sizes: list[int]
+ favicon_sizes: list[int]
+ icons_dir: Path = field(init=False)
+ touch: Path = field(init=False)
+ favicon: Path = field(init=False)
+
+ def __post_init__(self):
+ self.icons_dir = self.dir / 'icons'
+ self.touch = self.icons_dir / f'{self.name}-apple-180.png'
+ self.favicon = self.icons_dir / 'favicon.ico'
+
+
+def convert_svg_to_png(svg_file, png_file, size, background_color=None):
+ rsvg_options = [
+ '-w',
+ str(size),
+ '-h',
+ str(size),
+ '-o',
+ png_file,
+ ]
+ rsvg_options + ['-b', {background_color}] if background_color else []
+
+ subprocess.run(['rsvg-convert'] + rsvg_options + [svg_file], check=True)
+
+
+def compress_png(png_file):
+ subprocess.run(
+ ['pngquant', '--quality=70-95', '--ext', '.png', '--force', png_file],
+ check=True,
+ )
+ subprocess.run(['oxipng', png_file], check=True)
+
+
+def create_panel_icons(icon_pack, sizes):
+ for size in sizes:
+ app_png = icon_pack[size]
+ panel_png = app_png.with_name(f'{app_png.stem}-panel.png')
+ shutil.copyfile(app_png, panel_png)
+
+
+def create_hicolor_icons(svg_icon, icon_pack):
+ """Convert SVG icon to hicolor PNG icons."""
+ for size, png_file in icon_pack.items():
+ png_file.parent.mkdir(parents=True, exist_ok=True)
+ convert_svg_to_png(svg_icon, png_file, size)
+ compress_png(png_file)
+
+
+def create_ico_icon(icon_pack, sizes, ico_file):
+ infiles = [icon_pack[size] for size in sizes]
+ ico_file.parent.mkdir(parents=True, exist_ok=True)
+
+ subprocess.run(['convert', *infiles, ico_file], check=True)
+
+
+def create_hicolor_svg(src_svg, dest_svg):
+ dest_svg.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copyfile(src_svg, dest_svg)
+
+
+def create_mini_icons(pixmaps_dir):
+ pixmap_svgs = pixmaps_dir.glob('*.svg')
+
+ for svg_file in pixmap_svgs:
+ png_file = pixmaps_dir / f'{svg_file.stem}16.png'
+ convert_svg_to_png(svg_file, png_file, 16)
+ compress_png(png_file)
+
+
+def create_logo(deluge_png, pixmap_png):
+ pixmap_png.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copyfile(deluge_png, pixmap_png)
+
+
+def create_web_status_icons(src_dir: Path, dest_dir: Path):
+ """Web UI status icons from 16px icons."""
+ pngs_16px = src_dir.glob('*16.png')
+ dest_dir.mkdir(parents=True, exist_ok=True)
+ for path in pngs_16px:
+ if path.stem.startswith('tracker'):
+ continue
+ new_name = path.stem.replace('16', '') + '.png'
+ shutil.copyfile(path, dest_dir / new_name)
+
+
+def create_touch_icon(svg_file, png_file, size):
+ """Web icons with background color for Apple or Android"""
+ png_file.parent.mkdir(parents=True, exist_ok=True)
+ convert_svg_to_png(svg_file, png_file, size, background_color='#599EEE')
+ compress_png(png_file)
+
+
+def create_web_icons(app_pngs, sizes, dest_dir):
+ dest_dir.mkdir(parents=True, exist_ok=True)
+ for size in sizes:
+ app_png = app_pngs[size]
+ web_png = dest_dir / f'{app_png.stem}-{size}.png'
+ shutil.copyfile(app_png, web_png)
+
+
+def main():
+ data_dir = Path.cwd() / 'deluge' / 'ui' / 'data'
+ if not data_dir.is_dir():
+ exit(f'No path to UI data dir: {data_dir}')
+
+ # Create Deluge UI icons
+ icon_pack_sizes = [16, 22, 24, 32, 36, 48, 64, 72, 96, 128, 192, 256, 512]
+ panel_icon_sizes = [16, 22, 24]
+ ico_icon_sizes = [16, 32, 48, 64, 128, 256]
+ ui_icons = IconPack(
+ name='deluge',
+ dir=data_dir,
+ icon_sizes=icon_pack_sizes,
+ panel_sizes=panel_icon_sizes,
+ ico_sizes=ico_icon_sizes,
+ )
+
+ # Theme icons for GTK
+ create_hicolor_icons(ui_icons.logo_svg, ui_icons.theme_pngs)
+ create_hicolor_svg(ui_icons.logo_svg, ui_icons.theme_svg)
+ create_mini_icons(ui_icons.pixmaps_dir)
+ # Panel icon for systray
+ create_panel_icons(ui_icons.theme_pngs, ui_icons.panel_sizes)
+
+ # Deluge logos
+ create_ico_icon(ui_icons.theme_pngs, ui_icons.ico_sizes, ui_icons.logo_ico)
+ create_logo(ui_icons.theme_pngs[48], ui_icons.logo_png)
+
+ # Web UI Icons
+ web_icon_sizes = [32, 192, 512]
+ favicon_sizes = [16, 32, 48]
+ web_icons = WebIconPack(
+ name='deluge',
+ dir=data_dir / '..' / 'web',
+ icon_sizes=web_icon_sizes,
+ favicon_sizes=favicon_sizes,
+ )
+ create_web_icons(ui_icons.theme_pngs, web_icons.icon_sizes, web_icons.icons_dir)
+ create_web_status_icons(ui_icons.pixmaps_dir, web_icons.icons_dir)
+ create_touch_icon(ui_icons.logo_svg, web_icons.touch, 180)
+ create_ico_icon(ui_icons.theme_pngs, web_icons.favicon_sizes, web_icons.favicon)
+
+
+if __name__ == '__main__':
+ main()