Files
UniXNU/scripts/make-wallpaper-overlay.py
T
rpone ab11a8cb68 feat(scripts): iPadOS 27 kernel, driver, GPU addon and seed build steps
Source-driver and source-storage builds, the arm64e PAC rewrite for the Rust bridge, the IOAccelerator base ABI of 24A446, the bridge with mimalloc and link-time optimisation, the plugin with the prime list, addon options for a prime list, a pipeline pack and cache export, wallpaper overlay and seed changes, and payload, kernel and userdata steps for the new profile.
2026-10-28 09:20:55 +08:00

73 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""Build the overlay for the default iPadOS 17 wallpaper's layered animation with PNG images in place of its HEIC ones.
make-wallpaper-overlay.py SYSTEM_ROOT OUTPUT_DIR [ipados27|ipados27-floating]
SYSTEM_ROOT is the mounted OS volume of the IPSW (ipsw mount fs). The iPad7,1 variant of wallpaper 7570 (Flat, two image layers) is the
one PosterBoard picks on this device; its images are HEIC, which ImageIO cannot decode without a hardware HEVC decoder. OUTPUT_DIR gets
the animation's index.xml, assetManifest.caml and a main.caml that points at J120.png and J120-Dark.png next to it (converted with sips,
so this runs on macOS, and scaled to EDGE pixels). make-gpu-addon.py --wallpaper OUTPUT_DIR carries it to the kernel, which mounts it over the sealed animation.
With ipados27 the overlay is for iPadOS 27's variant of the same wallpaper (1032w-1376h, a background and a floating layer): its background
layer, whose two images (Background Light/Dark, 1620 x 1080) become Background-Light.png and Background-Dark.png at their own size.
With ipados27-floating it is the same variant's floating layer: its 13 images (blurred colour shapes with alpha) become PNG images, the
ones wider than 1000 pixels at a third of their size (the layers stretch their contents to their bounds; full size does not fit the boot
payload)."""
import subprocess
import sys
from pathlib import Path
PROFILES = {
None: (('Library/Wallpaper/Collections/iPadOS_17~ipad.wallpaperCollection/Wallpapers/7570.iPadOS_17_Flat-1024w-1366h@2x~ipad.wallpaper/'
'7570.iPadOS_17_Flat_Background-1024w-1366h@2x~ipad.ca'), {'J120': 'J120', 'J120-Dark': 'J120-Dark'}),
'ipados27': (('Library/Wallpaper/Collections/iPadOS_17~ipad.wallpaperCollection/Wallpapers/7570.iPadOS_17-1032w-1376h@2x~ipad.wallpaper/'
'7570.iPadOS_17_Background-1032w-1376h@2x~ipad.ca'),
{'Background%20Light': 'Background-Light', 'Background%20Dark': 'Background-Dark'}),
'ipados27-floating': (('Library/Wallpaper/Collections/iPadOS_17~ipad.wallpaperCollection/Wallpapers/7570.iPadOS_17-1032w-1376h@2x~ipad.wallpaper/'
'7570.iPadOS_17_Floating-1032w-1376h@2x~ipad.ca'),
{name.replace(' ', '%20'): name.replace(' ', '-') for name in (
'Aqua Dark', 'Aqua Light', 'Green Dark', 'Green Light', 'Orange Dark', 'Orange Light', 'Red Dark', 'Red Light',
'Red Landscape Patch', 'Red Yellow Edge Patch Dark', 'Red Yellow Edge Patch Light', 'Yellow Dark', 'Yellow Light')}),
}
# Longest edge of each profile's PNG images: None keeps the image's own size, a negative value divides images wider than its absolute
# value by three.
EDGES = {None: 2732, # iPadOS 17's HEIC images are 3416 pixels square; PNG at that size does not fit the boot payload
'ipados27': None, 'ipados27-floating': -1000}
def main():
if len(sys.argv) not in (3, 4) or len(sys.argv) == 4 and sys.argv[3] not in PROFILES:
sys.exit(__doc__)
profile = sys.argv[3] if len(sys.argv) == 4 else None
animation, images = PROFILES[profile]
edge = EDGES[profile]
source, output = Path(sys.argv[1]) / animation, Path(sys.argv[2])
if not (source / 'main.caml').is_file():
sys.exit('No wallpaper animation at ' + str(source))
if output.exists():
sys.exit('Refuse to overwrite ' + str(output))
output.mkdir(parents=True)
for name in ('index.xml', 'assetManifest.caml'):
(output / name).write_bytes((source / name).read_bytes())
main_caml = (source / 'main.caml').read_text()
for image, png in images.items():
main_caml = main_caml.replace(f'"/assets/{image}.HEIC"', f'"/{png}.png"').replace(f'"assets/{image}.HEIC"', f'"{png}.png"')
heic = source / 'assets' / (image.replace('%20', ' ') + '.HEIC')
size = []
if edge and edge > 0:
size = ['-Z', str(edge)]
elif edge:
width = int(subprocess.check_output(['sips', '-g', 'pixelWidth', str(heic)], text=True).split()[-1])
if width > -edge:
size = ['-Z', str(width // 3)]
subprocess.run(['sips', *size, '-s', 'format', 'png', str(heic), '--out', str(output / f'{png}.png')],
check=True, stdout=subprocess.DEVNULL)
if '.HEIC"/>' in main_caml:
sys.exit('main.caml still points at a HEIC image')
(output / 'main.caml').write_text(main_caml)
for path in sorted(output.iterdir()):
print(f'{path.stat().st_size:>10} {path.name}')
if __name__ == '__main__':
main()