summaryrefslogtreecommitdiffstats
path: root/deluge/scripts/create_icons.py
blob: 479505cf59ac971716237800483baf13a813b894 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
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()