gridranger
gridranger

Reputation: 403

Load UWP icon programmatically

I'm writing a Python-based launcher that is automatically populated form Windows' Start menu. I plan to extend it to include UWP apps. Listing and launching them isn't hard, but accessing their icons seems to be tricky.

As the apps reside under \program files\windowsapps\, their icons seem to be inaccessible due to permission issue. I don't plan to run my program elevated.

I have the current leads:

Upvotes: 0

Views: 42

Answers (1)

gridranger
gridranger

Reputation: 403

TLDR:

  1. get the 'store logo path' from the manifest
  2. don't believe it, but get the stem of it
  3. find the true paths based on the stem

Example:

This example will display the icon for an UWP app, by its name. Names can be listed by the powershell command:

Get-AppxPackage | Select-Object -ExpandProperty Name

Microsoft.WindowsCalculator is used for the example, but I've tried it out with other apps (Terminal, Spotify, Teams, Paint, ZuneMusic, DuckDuckGo, Outlook, WindowsStore etc.) and it worked well : )

Python code:

from pathlib import Path
from subprocess import run
from tkinter import Label, Tk

from PIL import Image, ImageTk


def get_powershell_output(command: str) -> str:
    process = run(command, capture_output=True, text=True, shell=True)
    return process.stdout.strip()


def get_icon_name(app_name: str) -> Path:
    command = f"""powershell "(Get-AppxPackage -Name {app_name} | Get-AppxPackageManifest).package.properties.logo" """
    return Path(get_powershell_output(command))


def get_install_path(app_name: str) -> Path:
    command = f"""powershell "(Get-AppxPackage -Name {app_name}).InstallLocation" """
    return Path(get_powershell_output(command))


def locate_icon(icon: Path, install_path: Path) -> Path:
    matches = install_path.glob(f"**/{icon.stem}*.png")
    # usually 3 matches (default, black, white), let's use default
    return list(matches)[0]


def show_icon(icon_path: Path) -> None:
    root = Tk()
    root.title("Display Icon")
    pil_image = Image.open(icon_path)
    tk_image = ImageTk.PhotoImage(pil_image)
    label = Label(root, image=tk_image)
    label.pack()
    root.mainloop()


def main(current_name: str) -> None:
    icon_path = get_icon_name(current_name)
    print(icon_path)
    # Assets\CalculatorStoreLogo.png

    install_path = get_install_path(current_name)
    print(install_path)
    # C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_11.2411.1.0_x64__8wekyb3d8bbwe

    selected_icon = locate_icon(icon_path, install_path)
    print(selected_icon)
    # C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_11.2411.1.0_x64__8wekyb3d8bbwe\Assets\CalculatorStoreLogo.scale-200.png

    show_icon(selected_icon)
    # see the proof


if __name__ == "__main__":
    main("Microsoft.WindowsCalculator")

Output: The console output as written in the code and the icon displayed in a TkInter window.

Upvotes: 0

Related Questions