[Scripts] Replace icon bash script with python version

Preferable to be working with Python scripts for easier development.

This is direct port of the original bash script with the slight
modification to also use pngquant to reduce file size further.
This commit is contained in:
Calum Lind 2023-11-19 18:23:00 +00:00
parent 5aa4d07816
commit 66eaea0059
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
2 changed files with 202 additions and 83 deletions

View File

@ -1,83 +0,0 @@
#!/bin/bash
# Convert Deluge svg icons to png.
#
# Requires
# * rsvg-convert
# * convert (ImageMagik)
# * oxipng
#
# Optional
# * ect (Efficient-Compression-Tool)
#
# Potential to combine pngquant with oxipng for further gains.
#
# Excellent compression with ECT but is much slower. For Linux need
# to build this tool from source.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
data_dir="$DIR/../ui/data"
OXI_COMPRESS="oxipng --opt 4 --interlace 0 --strip safe"
ECT_COMPRESS="ect --allfilters-b --pal_sort=120 -30060"
COMPRESS=$OXI_COMPRESS
# Create deluge png icon pack for all sizes.
for size in 16 22 24 32 36 48 64 72 96 128 192 256 512; do
mkdir -p $data_dir/icons/hicolor/${size}x${size}/apps
in_svg=$data_dir/pixmaps/deluge.svg
out_png=$data_dir/icons/hicolor/${size}x${size}/apps/deluge.png
rsvg-convert -w ${size} -h ${size} -o $out_png $in_svg
eval $COMPRESS $out_png
done
# Create deluge-panel png for systray.
for size in 16 22 24; do
in_png=$data_dir/icons/hicolor/${size}x${size}/apps/deluge.png
out_png=$data_dir/icons/hicolor/${size}x${size}/apps/deluge-panel.png
cp $in_png $out_png
done
# Create deluge.ico icon from pngs.
for size in 16 32 48 64 128 256; do
ico_infiles+="$data_dir/icons/hicolor/${size}x${size}/apps/deluge.png "
done
convert $ico_infiles $data_dir/pixmaps/deluge.ico
# Copy of deluge.svg to icon theme pack.
mkdir -p $data_dir/icons/hicolor/scalable/apps/
cp $data_dir/pixmaps/deluge.svg $data_dir/icons/hicolor/scalable/apps/deluge.svg
# Create 48px deluge.png.
cp $data_dir/icons/hicolor/48x48/apps/deluge.png $data_dir/pixmaps/deluge.png
# Create 16px png from deluge and status svgs.
for file in $data_dir/pixmaps/*.svg; do
out_png=${file%.*}16.png
rsvg-convert -w 16 -h 16 -o $out_png $file
eval $COMPRESS $out_png
done
# Copy 16px deluge and status pngs to webui icons folder.
for icon in $data_dir/pixmaps/*16.png; do
iconname=$(basename $icon)
cp $icon $data_dir/../web/icons/${iconname::-6}.png
done
rm $data_dir/../web/icons/tracker*.png
for size in 32 192 512; do
in_png=$data_dir/icons/hicolor/${size}x${size}/apps/deluge.png
out_png=$data_dir/../web/icons/deluge-${size}.png
cp $in_png $out_png
done
# Create apple and android touch icons with background colour.
apple_icon=$data_dir/../web/icons/deluge-apple-180.png
rsvg-convert -w 180 -h 180 -b '#599EEE' -o $apple_icon $data_dir/pixmaps/deluge.svg
eval $COMPRESS $apple_icon
# Create favicon.ico icon from pngs.
for size in 16 32 48; do
web_ico_infiles+="$data_dir/icons/hicolor/${size}x${size}/apps/deluge.png "
done
convert $web_ico_infiles $data_dir/../web/icons/favicon.ico

202
deluge/scripts/create_icons.py Executable file
View File

@ -0,0 +1,202 @@
#!/usr/bin/python3
#
# Create Deluge PNG icons from SVG
#
# Required image tools:
# * rsvg-convert
# * convert (ImageMagik)
# * oxipng
# * pngquant
#
import shutil
import subprocess
from pathlib import Path
from dataclasses import dataclass, field
@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()