feat: add MSIX artifact sink and source

This commit is contained in:
yyc12345 committed 2026-10-15 16:03:46 +08:00
1 parent e2c15f7145
commit 9e41900596
7 files changed
+209 -5

No files matched your search

@@ -2,6 +2,7 @@ from .common import Sink
from .tempart_sink import TempArtSink
from .fdart_sink import FdArtSink
from .icoart_sink import IcoArtSink
from .msixart_sink import MsixArtSink
from .icnsart_sink import IcnsArtSink
__all__ = [
@@ -9,5 +10,6 @@ __all__ = [
"TempArtSink",
"FdArtSink",
"IcoArtSink",
"MsixArtSink",
"IcnsArtSink"
]
@@ -0,0 +1,105 @@
from dataclasses import dataclass
from .common import Sink
from ..address import Address, AddressDomain
from ..environment import Environment
from ..utils import (
Artifact,
MsixCategory,
MsixAppLogoKind,
MsixAppPlatedKind,
resolve_msix_scale,
check_vart,
)
from ...lowlevel import artio, artrdr
from ...logger import HIGHLEVEL_LOGGER as LOGGER
@dataclass(frozen=True)
class MsixArtSinkHint:
kind: MsixCategory
name: str
class MsixArtSink(Sink):
__kind: MsixCategory
__name: str
def __init__(self, kind: MsixCategory, name: str) -> None:
self.__kind = kind
self.__name = name
@property
def address(self) -> Address:
return Address(AddressDomain.WinMsixOutput, str(self.__kind), self.__name)
def push(self, env: Environment, art: Artifact) -> None:
LOGGER.info(
'Saving Windows MSIX artifact with kind "%s" and name "%s".',
self.__kind,
self.__name,
)
check_vart(art)
# different category need entirely different push strategies
match self.__kind:
case MsixCategory.Application:
self.__push_app(env, art)
case MsixCategory.Extension:
self.__push_ext(env, art)
case _:
raise ValueError(f"Unknown MSIX category: {self.__kind}")
def __push_app(self, env: Environment, art: Artifact) -> None:
# push by sub-kind
for kind in MsixAppLogoKind:
size = kind.to_size()
# push no suffix variant
# TODO: We currently brutely assume all artifacts are squared.
# This premise may be broken when meeting with wide tile logo and etc.
# But currently we doesn't support them.
# So these code need to be changed in future.
hw = size[0]
(thumbnail,) = artrdr.render_thumbnail(art, (hw,))
dst = env.msix_app_output_artifact(kind, None, None, None, self.__name)
artio.save_artifact(thumbnail, dst)
# push scale variants
hws = tuple(resolve_msix_scale(hw, scale) for scale in env.prologue.msix_scales)
for scale, thumbnail in zip(
env.prologue.msix_scales, artrdr.render_thumbnail(art, hws)
):
dst = env.msix_app_output_artifact(kind, scale, None, None, self.__name)
artio.save_artifact(thumbnail, dst)
# push special variants for Square44x44
if kind == MsixAppLogoKind.Square44x44:
for targetsize, thumbnail in zip(
env.prologue.msix_app44_targetsizes,
artrdr.render_thumbnail(art, env.prologue.msix_app44_targetsizes),
):
for plated in MsixAppPlatedKind:
dst = env.msix_app_output_artifact(
kind, None, targetsize, plated, self.__name
)
artio.save_artifact(thumbnail, dst)
def __push_ext(self, env: Environment, art: Artifact) -> None:
# push default with 44x44 size
# TODO: These hardcode code is also shitty
# It should be improved like ``MsixAppLogoKind`.to_size()`
hw = 44
(thumbnail,) = artrdr.render_thumbnail(art, (hw,))
dst = env.msix_ext_output_artifact(None, self.__name)
artio.save_artifact(thumbnail, dst)
# push targetsize variants
for targetsize, thumbnail in zip(
env.prologue.msix_ext_targetsizes,
artrdr.render_thumbnail(art, env.prologue.msix_ext_targetsizes),
):
dst = env.msix_ext_output_artifact(targetsize, self.__name)
artio.save_artifact(thumbnail, dst)
def push_hint(self) -> MsixArtSinkHint:
return MsixArtSinkHint(self.__kind, self.__name)
@@ -6,6 +6,7 @@ from .blender_source import BlenderSource
from .tempart_source import TempArtSource
from .fdart_source import FdArtSource
from .icoart_source import IcoArtSource
from .msixart_source import MsixArtSource
from .icnsart_source import IcnsArtSource
@@ -18,5 +19,6 @@ __all__ = [
"TempArtSource",
"FdArtSource",
"IcoArtSource",
"MsixArtSource",
"IcnsArtSource",
]
@@ -19,8 +19,8 @@ class IcnsArtSource(Source):
def address(self) -> Address:
return Address(AddressDomain.MacIcnsOutput, str(self.__kind), self.__name)
def link_to(self, env: Environment, mac_sink: IcnsArtSink) -> None:
sink_hint = mac_sink.push_hint()
def link_to(self, env: Environment, icns_sink: IcnsArtSink) -> None:
sink_hint = icns_sink.push_hint()
LOGGER.info(
'Duplicating macOS ICNS artifact from kind "%s" name "%s" to kind "%s" name "%s".',
self.__kind,
@@ -19,8 +19,8 @@ class IcoArtSource(Source):
def address(self) -> Address:
return Address(AddressDomain.WinIcoOutput, str(self.__kind), self.__name)
def link_to(self, env: Environment, win_sink: IcoArtSink) -> None:
sink_hint = win_sink.push_hint()
def link_to(self, env: Environment, ico_sink: IcoArtSink) -> None:
sink_hint = ico_sink.push_hint()
LOGGER.info(
'Duplicating Windows ICO artifact from kind "%s" name "%s" to kind "%s" name "%s".',
self.__kind,
@@ -0,0 +1,84 @@
from .common import Source
from ..address import Address, AddressDomain
from ..environment import Environment
from ..sink.msixart_sink import MsixArtSink, MsixArtSinkHint
from ..utils import MsixCategory, MsixAppLogoKind, MsixAppPlatedKind
from ...lowlevel import artio
from ...logger import HIGHLEVEL_LOGGER as LOGGER
class MsixArtSource(Source):
__kind: MsixCategory
__name: str
def __init__(self, kind: MsixCategory, name: str) -> None:
self.__kind = kind
self.__name = name
@property
def address(self) -> Address:
return Address(AddressDomain.WinMsixOutput, str(self.__kind), self.__name)
def link_to(self, env: Environment, msix_sink: MsixArtSink) -> None:
sink_hint = msix_sink.push_hint()
LOGGER.info(
'Duplicating Windows MSIX artifact from kind "%s" name "%s" to kind "%s" name "%s".',
self.__kind,
self.__name,
sink_hint.kind,
sink_hint.name,
)
# different category need entirely different link strategies
match self.__kind:
case MsixCategory.Application:
self.__link_to_app(env, sink_hint)
case MsixCategory.Extension:
self.__link_to_ext(env, sink_hint)
case _:
raise ValueError(f"Unknown MSIX category: {self.__kind}")
def __link_to_app(self, env: Environment, sink_hint: MsixArtSinkHint) -> None:
# link by sub-kind
for kind in MsixAppLogoKind:
# link no suffix variant
artio.link_artifact(
env.msix_app_output_artifact(kind, None, None, None, self.__name),
env.msix_app_output_artifact(kind, None, None, None, sink_hint.name),
)
# link scale variants
for scale in env.prologue.msix_scales:
artio.link_artifact(
env.msix_app_output_artifact(kind, scale, None, None, self.__name),
env.msix_app_output_artifact(
kind, scale, None, None, sink_hint.name
),
)
# link special variants for Square44x44
if kind == MsixAppLogoKind.Square44x44:
for targetsize in env.prologue.msix_app44_targetsizes:
for plated in MsixAppPlatedKind:
artio.link_artifact(
env.msix_app_output_artifact(
kind, None, targetsize, plated, self.__name
),
env.msix_app_output_artifact(
kind, None, targetsize, plated, sink_hint.name
),
)
def __link_to_ext(self, env: Environment, sink_hint: MsixArtSinkHint) -> None:
# link default
artio.link_artifact(
env.msix_ext_output_artifact(None, self.__name),
env.msix_ext_output_artifact(None, sink_hint.name),
)
# link targetsize variants
for targetsize in env.prologue.msix_ext_targetsizes:
artio.link_artifact(
env.msix_ext_output_artifact(targetsize, self.__name),
env.msix_ext_output_artifact(targetsize, sink_hint.name),
)
+12 -1
View File
@@ -20,6 +20,17 @@ def check_fd_hw(hw: int) -> None:
)
def resolve_msix_scale(hw: int, scale: int) -> int:
"""
Resolve given MSIX scale value with original width/height.
:param hw: The height or width before scale for resolving.
:param scale: The scale value for resolving.
:returns: The height/width after applying scale value.
"""
return hw * scale // 100
def check_msix_scale(hw: int, scale: int) -> None:
"""
Check whether given MSIX scale value is valid.
@@ -32,7 +43,7 @@ def check_msix_scale(hw: int, scale: int) -> None:
if scale <= 100:
raise ValueError(f"Invalid scale value for MSIX icon variant: {scale}")
# the image scaled after this value must not exceed VART_HW
scaled_hw = hw * scale // 100
scaled_hw = resolve_msix_scale(hw, scale)
if scaled_hw > VART_HW:
raise ValueError(f"Scale value is too large for MSIX icon variant: {scale}")