diff --git a/.gitignore b/.gitignore index bc9f191464..032783fb59 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,7 @@ /resources/mozilla-ca-certs.pem /resources/user-agent-data.json /resources/piper-voices.json -/icons/icns/*.iconset +/icons/icns/*/*.iconset /setup/installer/windows/calibre/build.log /setup/pyqt_enums /tags diff --git a/bypy/macos.conf b/bypy/macos.conf index 4d79529b72..467cbb656c 100644 --- a/bypy/macos.conf +++ b/bypy/macos.conf @@ -1,5 +1,5 @@ # Requires installation of XCode 16.2 and -# python3 -m pip install certifi html5lib +# python3 -m pip install certifi html5lib icnsutil vm_name 'macos-calibre' root '/Users/Shared/calibre-build' diff --git a/bypy/macos/__main__.py b/bypy/macos/__main__.py index fe419175e5..502fcfe461 100644 --- a/bypy/macos/__main__.py +++ b/bypy/macos/__main__.py @@ -19,6 +19,8 @@ import zipfile from functools import partial, reduce from itertools import repeat +import icnsutil + from bypy.constants import OUTPUT_DIR, PREFIX, PYTHON, python_major_minor_version from bypy.constants import SRC as CALIBRE_DIR from bypy.freeze import extract_extension_modules, fix_pycryptodome, freeze_python, is_package_dir, path_to_freeze_dir @@ -49,6 +51,20 @@ EXPECTED_ARCHES = {'x86_64', 'arm64'} MINIMUM_SYSTEM_VERSION = '14.0.0' +def generate_icns(light_iconset: str, dark_iconset: str, output_path: str) -> None: + def add_iconset(icns, path): + for img in os.listdir(path): + if img.endswith('.png'): + icns.add_media(file=os.path.join(path, img)) + dark_icns = icnsutil.IcnsFile() + add_iconset(dark_icns, dark_iconset) + dark_icns.write(output_path, toc=True) + light_icns = icnsutil.IcnsFile() + add_iconset(light_icns, light_iconset) + light_icns.add_media(icnsutil.IcnsType.key_from_readable('dark'), file=output_path) + light_icns.write(output_path, toc=True) + + def compile_launcher_lib(contents_dir, base, pyver, inc_dir): print('\tCompiling calibre_launcher.dylib') env, env_vals = [], [] @@ -223,6 +239,7 @@ class Freeze: @flush def run_tests(self): + print('Running tests...', flush=True) self.test_runner(join(self.contents_dir, 'MacOS', 'calibre-debug'), self.contents_dir) @flush @@ -377,9 +394,10 @@ class Freeze: if not icons: raise SystemExit('Failed to find icns format icons') for x in icons: - subprocess.check_call([ - 'iconutil', '-c', 'icns', x, '-o', join( - self.resources_dir, basename(x).partition('.')[0] + '.icns')]) + output_icns = join(self.resources_dir, basename(x).partition('.')[0] + '.icns') + xd = x.replace('/light/', '/dark/') + assert x != xd + generate_icns(x, xd, output_icns) for helpers in (self.helpers_dir,): os.makedirs(helpers) cdir = dirname(helpers) diff --git a/icons/icns/make_iconsets.py b/icons/icns/make_iconsets.py index 48b9dc1974..45ee5db9c8 100755 --- a/icons/icns/make_iconsets.py +++ b/icons/icns/make_iconsets.py @@ -41,12 +41,11 @@ with tempfile.TemporaryDirectory() as tdir: frame = render_frame(mode, sz) icon = os.path.join(tdir, f'icon-{sz}.png') render_svg(src, int(shrink_factor * sz), icon) - subprocess.check_call(f'convert {frame} {icon} -gravity center -compose over -composite {iname}'.split()) + subprocess.check_call(f'magick {frame} {icon} -gravity center -compose over -composite {iname}'.split()) for mode in ('light', 'dark'): subdir = mode - if not os.path.exists(subdir): - os.mkdir(subdir) + os.makedirs(subdir, exist_ok=True) for name, src in sources.items(): iconset = j(subdir, name + '.iconset') if os.path.exists(iconset): @@ -54,19 +53,19 @@ with tempfile.TemporaryDirectory() as tdir: os.mkdir(iconset) os.chdir(iconset) try: - for sz in (16, 32, 128, 256, 512, 1024): + for sz in (16, 32, 64, 128, 256, 512, 1024): iname = f'icon_{sz}x{sz}.png' iname2x = f'icon_{sz // 2}x{sz // 2}@2x.png' if sz < 128: render_svg(src, sz, iname) else: render_framed(mode, sz, iname) + subprocess.check_call(['optipng', '-o7', '-strip', 'all', iname]) if sz > 16: shutil.copy2(iname, iname2x) - if sz > 512: + if sz > 512 or sz == 64: os.remove(iname) - for name in (iname, iname2x): - if os.path.exists(name): - subprocess.check_call(['optipng', '-o7', '-strip', 'all', name]) + if sz == 128: + os.remove(iname2x) finally: os.chdir('../..')