Last active
February 21, 2023 20:38
-
-
Save mentlerd/8e2f73540aa2e2d0eb55bbe94b8030ce to your computer and use it in GitHub Desktop.
Transparent Windows user avatar
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import subprocess | |
import pathlib | |
import winreg | |
# | |
# This script turned out to be quite large, so might as well document the recipe here.. | |
# | |
# Windows (like many services...) does not support transparent backgrounds for profile | |
# pictures natively, it squashes beautiful, lossless, transparent .png files into | |
# various .jpg files with some horrible rescaling algorithm. | |
# | |
# Luckily it can be coerced into showing .png files all around the OS, and even gets | |
# transparency right! | |
# | |
# (As long as you are using a local user account, this won't work with Microsoft accounts.) | |
# | |
# To do so, you want to change some registry keys: | |
# | |
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AccountPicture\Users\<SID> | |
# Image32=... | |
# Image40=... | |
# Image64=... | |
# | |
# This however cannot be done by mere mortals, not even administrators. You have to use the | |
# hidden SYSTEM user. For which it is best to use PsExec from SysInternals | |
# | |
# So the full recipe is: | |
# Generate PNG files from your SVG with this very script | |
# > $ whoami | |
# > dave-pc\dave | |
# | |
# > wmic useraccount where name = 'dave' | |
# > SID | |
# > ... | |
# | |
# > psexec -i -d -s c:\windows\regedit.exe | |
# | |
# PS.: I am aware this is not particularly nice/very Pythonic code - it does what I need, nothing more | |
# | |
parser = argparse.ArgumentParser( | |
prog = "avatargen", | |
description = "Generate various resolution images for using as a profile picture from a vector image", | |
epilog = ".. yes the hundredth iteration turned out great, but can we do better?" | |
) | |
parser.add_argument('filename') | |
# Configuration | |
file = pathlib.Path(parser.parse_args().filename) | |
targets = [ | |
# Windows | |
{ | |
"name": "{}", | |
"area": "bounds_circle", | |
"sizes": [32, 40, 48, 64, 96, 192, 208, 240, 424, 448, 1080], | |
}, | |
# Special sizes for "special" sites | |
{ | |
"name": "github{}", | |
"area": "bounds_circle", | |
"sizes": [460] | |
}, | |
{ | |
"name": "google{}", | |
"area": "bounds_circle", | |
"sizes": [500] | |
}, | |
# Generic | |
{ | |
"name": "square{}", | |
"area": "bounds_square", | |
"sizes": [512] | |
}, | |
{ | |
"name": "circle{}", | |
"area": "bounds_circle", | |
"sizes": [512] | |
} | |
] | |
print("Scanning for required software") | |
def enum_reg_keys(node): | |
for index in range(1024): | |
try: | |
yield winreg.EnumKey(node, index) | |
except EnvironmentError: | |
break | |
inkscape = None | |
magick = None | |
roots = [ | |
r'Software\Microsoft\Windows\CurrentVersion\Uninstall', | |
r'Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall' | |
] | |
for root in roots: | |
root = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, root) | |
for app in enum_reg_keys(root): | |
app = winreg.OpenKey(root, app) | |
icon = None | |
try: | |
icon = winreg.QueryValueEx(app, 'DisplayIcon')[0] | |
except EnvironmentError: | |
continue | |
icon = pathlib.Path(icon) | |
if icon.stem == "inkscape" and icon.suffix == ".exe": | |
inkscape = icon.with_suffix('.com') | |
if icon.stem == "ImageMagick": | |
magick = icon.with_name('magick.exe') | |
print(f"Found Inkscape: {inkscape}") | |
print(f"Found ImageMagick: {magick}") | |
bounds = {} | |
print("Enumerating SVG elements looking for boundary elements") | |
output = subprocess.check_output([inkscape, '--query-all', file], shell=True) | |
for line in output.decode('utf-8').splitlines(): | |
line = line.split(',', 5) | |
if line[0].startswith("bounds_"): | |
x = float(line[1]) | |
y = float(line[2]) | |
w = float(line[3]) | |
h = float(line[4]) | |
bounds[line[0]] = [int(x), int(y), int(x+w), int(y+h)] | |
print("Rendering to intermediary supersized bitmaps") | |
actions = [ | |
f"file-open:{file}", | |
f"export-type:png", | |
] | |
for i, target in enumerate(targets): | |
for size in target.get('sizes'): | |
name = target.get('name').format(size) | |
area = bounds.get(target.get('area')) | |
area = ':'.join([str(v) for v in area]) | |
res = size * 2 | |
actions += [ | |
f"export-filename: out/{name}", | |
f"export-width: {res}", | |
f"export-height: {res}", | |
f"export-id: beaver", | |
f"export-id-only", | |
f"export-area: {area}", | |
f"export-do" | |
] | |
actions = "; ".join(actions) | |
subprocess.check_call([inkscape, f'--actions={actions}'], shell=True) | |
print("Downsampling to final resolutions") | |
print(targets) | |
for target in targets: | |
for size in target.get('sizes'): | |
name = target.get('name').format(size) | |
subprocess.check_call([ | |
magick, | |
f'out/{name}.png', '-resize', '50%', | |
f'out/{name}.png' | |
], shell=True) | |
print("Finished") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment