Compare commits
4
Commits
1d48f54c40
...
80738d1254
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80738d1254 | ||
|
|
c54ae438c1 | ||
|
|
f33523259a | ||
|
|
96e0eab9d2 |
@@ -1,25 +1,32 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from .assemblicon.context import Context
|
||||
from .assemblicon.context import Prerequisite, Context, AdvancedContext
|
||||
from .assemblicon.utils import setup_logging
|
||||
from .std_icons import build_standard_icons
|
||||
from .ext_icons import build_ext_icons
|
||||
from .nostd_icons import build_non_standard_icons
|
||||
from .cli import parse
|
||||
|
||||
|
||||
def main() -> None:
|
||||
opts = parse()
|
||||
|
||||
setup_logging()
|
||||
|
||||
repository_root = Path(__file__).resolve().parent.parent.parent.parent
|
||||
iconset_input = repository_root / "src"
|
||||
iconset_output = repository_root / "artifact"
|
||||
ctx = Context(iconset_input, iconset_output)
|
||||
prereq = Prerequisite(
|
||||
iconset_input, iconset_output, opts.svg_render.to_assemblicon_type()
|
||||
)
|
||||
ctx = Context(prereq)
|
||||
advctx = AdvancedContext(ctx)
|
||||
|
||||
try:
|
||||
_build_icons(ctx)
|
||||
_build_icons(advctx)
|
||||
except BaseException as e:
|
||||
logging.fatal("Runtime error: %s", e)
|
||||
|
||||
|
||||
def _build_icons(ctx: Context) -> None:
|
||||
def _build_icons(ctx: AdvancedContext) -> None:
|
||||
build_standard_icons(ctx)
|
||||
#build_ext_icons(ctx)
|
||||
build_non_standard_icons(ctx)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import PIL.Image
|
||||
from .utils import Artifact, ArtifactFile
|
||||
@@ -23,3 +24,7 @@ def load_artifact(p: Path) -> ArtifactFile:
|
||||
def save_artifact(art: Artifact, p: Path) -> None:
|
||||
logging.info("Saving artifact: %s", p)
|
||||
art.save(p, format="PNG")
|
||||
|
||||
|
||||
def dup_artifact(src: Path, dst: Path) -> None:
|
||||
shutil.copyfile(src, dst)
|
||||
|
||||
@@ -100,9 +100,9 @@ _ART_MAC: str = "macos"
|
||||
_DEFAULT_SVG_CONFIG = artrender.SvgConfig(VANILLA_ARTIFACT_HW, VANILLA_ARTIFACT_HW)
|
||||
_DEFAULT_BLD_CONFIG = artrender.BlenderConfig(VANILLA_ARTIFACT_HW, VANILLA_ARTIFACT_HW)
|
||||
|
||||
# TODO: For easy testing, we only build 48x48.
|
||||
# TODO: For easy testing, we only build 32x32 and 48x48.
|
||||
# Enable full generation after testing.
|
||||
_FD_THUMBNAIL_HWS: tuple[int, ...] = (48,)
|
||||
_FD_THUMBNAIL_HWS: tuple[int, ...] = (32, 48)
|
||||
# _FD_THUMBNAIL_HWS: tuple[int, ...] = (16, 32, 48, 64, 128, 256)
|
||||
|
||||
|
||||
@@ -112,7 +112,30 @@ class AdvancedContext:
|
||||
def __init__(self, ctx: Context) -> None:
|
||||
self.__context = ctx
|
||||
|
||||
# construct basic layout of temporary directory and output directory.
|
||||
# construct basic layout of temporary directory
|
||||
self.__context.temporary_artifact(_TEMP_USER_DIR).mkdir(
|
||||
parents=True, exist_ok=True
|
||||
)
|
||||
self.__context.temporary_artifact(_TEMP_LIB_DIR, _TEMP_LIB_ALLOC_DIR).mkdir(
|
||||
parents=True, exist_ok=True
|
||||
)
|
||||
self.__context.temporary_artifact(_TEMP_LIB_DIR, _TEMP_LIB_STABLE_DIR).mkdir(
|
||||
parents=True, exist_ok=True
|
||||
)
|
||||
# and output directory
|
||||
for hw in _FD_THUMBNAIL_HWS:
|
||||
for kind in FdContext:
|
||||
self.__context.output_artifact(f"{hw}x{hw}", str(kind)).mkdir(
|
||||
parents=True, exist_ok=True
|
||||
)
|
||||
for kind in WinCategory:
|
||||
self.__context.output_artifact(_ART_WIN, str(kind)).mkdir(
|
||||
parents=True, exist_ok=True
|
||||
)
|
||||
for kind in MacCategory:
|
||||
self.__context.output_artifact(_ART_MAC, str(kind)).mkdir(
|
||||
parents=True, exist_ok=True
|
||||
)
|
||||
|
||||
def __enter__(self) -> "AdvancedContext":
|
||||
return self
|
||||
@@ -207,7 +230,10 @@ class AdvancedContext:
|
||||
self.__intern_render_svg(src, dst, cfg)
|
||||
|
||||
def render_svg_then_load(
|
||||
self, src: Path, dst: Optional[Path], cfg: SvgConfig = _DEFAULT_SVG_CONFIG
|
||||
self,
|
||||
src: Path,
|
||||
dst: Optional[Path] = None,
|
||||
cfg: SvgConfig = _DEFAULT_SVG_CONFIG,
|
||||
) -> Artifact:
|
||||
"""
|
||||
Render given SVG to PNG file, then load it directly.
|
||||
@@ -248,7 +274,10 @@ class AdvancedContext:
|
||||
self.__intern_render_blender(src, dst, cfg)
|
||||
|
||||
def render_blender_then_load(
|
||||
self, src: Path, dst: Optional[Path], cfg: BlenderConfig = _DEFAULT_BLD_CONFIG
|
||||
self,
|
||||
src: Path,
|
||||
dst: Optional[Path] = None,
|
||||
cfg: BlenderConfig = _DEFAULT_BLD_CONFIG,
|
||||
) -> Artifact:
|
||||
"""
|
||||
Render given Blender composition to PNG file, then load it directly.
|
||||
@@ -285,6 +314,15 @@ class AdvancedContext:
|
||||
dst = self.__fd_artifact(hw, kind, name)
|
||||
artio.save_artifact(thumbnail, dst)
|
||||
|
||||
def dup_fd_artifact(
|
||||
self, src_kind: FdContext, src_name: str, dst_kind: FdContext, dst_name: str
|
||||
) -> None:
|
||||
for hw in _FD_THUMBNAIL_HWS:
|
||||
artio.dup_artifact(
|
||||
self.__fd_artifact(hw, src_kind, src_name),
|
||||
self.__fd_artifact(hw, dst_kind, dst_name),
|
||||
)
|
||||
|
||||
def __win_artifact(self, kind: WinCategory, name: str) -> Path:
|
||||
return self.__context.output_artifact(_ART_WIN, str(kind), f"{name}.ico")
|
||||
|
||||
@@ -299,6 +337,14 @@ class AdvancedContext:
|
||||
)
|
||||
artrender.render_ico(art, self.__win_artifact(kind, name))
|
||||
|
||||
def dup_win_artifact(
|
||||
self, src_kind: WinCategory, src_name: str, dst_kind: WinCategory, dst_name: str
|
||||
) -> None:
|
||||
artio.dup_artifact(
|
||||
self.__win_artifact(src_kind, src_name),
|
||||
self.__win_artifact(dst_kind, dst_name),
|
||||
)
|
||||
|
||||
def __mac_artifact(self, kind: MacCategory, name: str) -> Path:
|
||||
return self.__context.output_artifact(_ART_MAC, str(kind), f"{name}.icns")
|
||||
|
||||
@@ -311,4 +357,12 @@ class AdvancedContext:
|
||||
logging.info("Saving macOS-only artifact with kind %s and name %s.", kind, name)
|
||||
artrender.render_icns(art, self.__mac_artifact(kind, name))
|
||||
|
||||
def dup_mac_artifact(
|
||||
self, src_kind: MacCategory, src_name: str, dst_kind: MacCategory, dst_name: str
|
||||
) -> None:
|
||||
artio.dup_artifact(
|
||||
self.__mac_artifact(src_kind, src_name),
|
||||
self.__mac_artifact(dst_kind, dst_name),
|
||||
)
|
||||
|
||||
# endregion
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import argparse
|
||||
import enum
|
||||
from dataclasses import dataclass
|
||||
from .assemblicon import artrender
|
||||
|
||||
|
||||
class SvgRender(enum.StrEnum):
|
||||
Inkscape = "inkscape"
|
||||
ReSvg = "resvg"
|
||||
|
||||
def to_assemblicon_type(self) -> artrender.SvgRenderKind:
|
||||
match self:
|
||||
case SvgRender.Inkscape:
|
||||
return artrender.SvgRenderKind.Inkscape
|
||||
case SvgRender.ReSvg:
|
||||
return artrender.SvgRenderKind.ReSvg
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Cli:
|
||||
svg_render: SvgRender
|
||||
|
||||
|
||||
def parse() -> Cli:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="Aurora Icon Set Builder",
|
||||
description="The Programmatic Icon Assembly Workflow for Aurora Icon Set.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--svg-render",
|
||||
dest="svg_render",
|
||||
action="store",
|
||||
type=SvgRender,
|
||||
default=SvgRender.Inkscape,
|
||||
help="The render used for rendering SVG into PNG.",
|
||||
metavar="RENDER",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
return Cli(
|
||||
svg_render=args.svg_render,
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
from ..assemblicon.context import Context
|
||||
from .image_icons import build_image_icons
|
||||
|
||||
|
||||
def build_ext_icons(ctx: Context) -> None:
|
||||
build_image_icons(ctx)
|
||||
@@ -1,5 +1,6 @@
|
||||
from ..assemblicon.context import Context
|
||||
from ..assemblicon.context import AdvancedContext
|
||||
from .mimetype_icons import build_mimetype_icons
|
||||
|
||||
|
||||
def build_non_standard_icons(ctx: Context) -> None:
|
||||
pass
|
||||
def build_non_standard_icons(ctx: AdvancedContext) -> None:
|
||||
build_mimetype_icons(ctx)
|
||||
|
||||
+17
-13
@@ -1,7 +1,6 @@
|
||||
import PIL.Image
|
||||
import PIL.ImageEnhance
|
||||
from ..assemblicon.artrender import render_svg, render_ico, SvgConfig
|
||||
from ..assemblicon.context import Context
|
||||
from ..assemblicon.context import AdvancedContext, FdContext, WinCategory, MacCategory
|
||||
from ..assemblicon.utils import Artifact
|
||||
from ..assemblicon.geometry import MinMaxRect, PosSizeRect
|
||||
from ..assemblicon.artio import load_input_artifact, save_artifact
|
||||
@@ -11,23 +10,26 @@ from ..assemblicon.artproc import (
|
||||
HorizontalAnchor,
|
||||
)
|
||||
|
||||
|
||||
def build_mimetype_icons(ctx: AdvancedContext) -> None:
|
||||
_build_image_icons(ctx)
|
||||
|
||||
|
||||
IMAGE_INNER_RECT_MINMAX = MinMaxRect(20 * 4, 52 * 4, 236 * 4, 204 * 4)
|
||||
IMAGE_INNER_RECT_POSSIZE = IMAGE_INNER_RECT_MINMAX.to_pos_size_rect()
|
||||
|
||||
|
||||
def build_image_icons(ctx: Context) -> None:
|
||||
def _build_image_icons(ctx: AdvancedContext) -> None:
|
||||
# build image base
|
||||
image_base = render_svg(
|
||||
image_base = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "image-base.svg"),
|
||||
ctx.temporary_artifact("component", "image-base.png"),
|
||||
SvgConfig(1024, 1024),
|
||||
)
|
||||
# load image base
|
||||
with image_base:
|
||||
_build_jpg_icon(ctx, image_base)
|
||||
|
||||
|
||||
def _build_jpg_icon(ctx: Context, base: Artifact) -> None:
|
||||
def _build_jpg_icon(ctx: AdvancedContext, base: Artifact) -> None:
|
||||
jpg_image = base.copy()
|
||||
|
||||
jpg_image_inner = load_input_artifact(
|
||||
@@ -58,10 +60,12 @@ def _build_jpg_icon(ctx: Context, base: Artifact) -> None:
|
||||
jpg_image.paste(
|
||||
bestfit_jpg_image_inner, IMAGE_INNER_RECT_POSSIZE.to_pillow_tuple()
|
||||
)
|
||||
|
||||
# build artifacts
|
||||
save_artifact(jpg_image, ctx.temporary_artifact("ext", "jpg-image.png"))
|
||||
render_ico(
|
||||
ctx,
|
||||
jpg_image,
|
||||
ctx.output_artifact("ext", "jpg-image.ico"),
|
||||
)
|
||||
# save for FD
|
||||
ctx.save_fd_artifact(jpg_image, FdContext.MimeTypes, "image-jpeg")
|
||||
# use image/jpeg as the default image icon
|
||||
ctx.dup_fd_artifact(FdContext.MimeTypes, "image-jpeg", FdContext.MimeTypes, "image-x-generic")
|
||||
# save for windows and mac
|
||||
ctx.save_win_artifact(jpg_image, WinCategory.Extension, "jpg")
|
||||
ctx.save_mac_artifact(jpg_image, MacCategory.Extension, "jpg")
|
||||
@@ -1,6 +1,6 @@
|
||||
from ..assemblicon.context import Context
|
||||
from ..assemblicon.context import AdvancedContext
|
||||
from .action_icons import build_action_icons
|
||||
|
||||
|
||||
def build_standard_icons(ctx: Context) -> None:
|
||||
def build_standard_icons(ctx: AdvancedContext) -> None:
|
||||
build_action_icons(ctx)
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
from pathlib import Path
|
||||
import PIL.Image
|
||||
from ..assemblicon.artrender import render_svg, SvgConfig
|
||||
from ..assemblicon.context import Context
|
||||
from ..assemblicon.utils import Artifact
|
||||
from ..assemblicon.artio import save_artifact
|
||||
from ..assemblicon.context import AdvancedContext, FdContext
|
||||
|
||||
|
||||
def build_action_icons(ctx: Context) -> None:
|
||||
def build_action_icons(ctx: AdvancedContext) -> None:
|
||||
_build_go_icons(ctx)
|
||||
|
||||
|
||||
def _build_go_icons(ctx: Context) -> None:
|
||||
def _build_go_icons(ctx: AdvancedContext) -> None:
|
||||
# build go-* base
|
||||
go_base = render_svg(
|
||||
ctx.input_artifact("component", "go-base.svg"),
|
||||
ctx.temporary_artifact("component", "go-base.png"),
|
||||
SvgConfig(1024, 1024),
|
||||
go_base = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "go-base.svg")
|
||||
)
|
||||
# build go-* shining
|
||||
go_inner_shining = render_svg(
|
||||
go_inner_shining = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "go-inner-shining.svg"),
|
||||
ctx.temporary_artifact("component", "go-inner-shining.png"),
|
||||
SvgConfig(1024, 1024),
|
||||
)
|
||||
# build go-* inner
|
||||
go_inner = render_svg(
|
||||
go_inner = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "go-inner.svg"),
|
||||
ctx.temporary_artifact("component", "go-inner.png"),
|
||||
SvgConfig(1024, 1024),
|
||||
)
|
||||
|
||||
with go_base, go_inner_shining, go_inner:
|
||||
@@ -36,8 +26,9 @@ def _build_go_icons(ctx: Context) -> None:
|
||||
go = go_base.copy()
|
||||
# render shining with inner mask
|
||||
go.paste(go_inner_shining, (0, 0), go_mask)
|
||||
# save as image
|
||||
save_artifact(go, ctx.output_artifact(f"go-{part}.png"))
|
||||
|
||||
# save as FD action
|
||||
ctx.save_fd_artifact(go, FdContext.Actions, f'go-{part}')
|
||||
|
||||
# rotate it for next calling
|
||||
go_mask = go_mask.transpose(PIL.Image.Transpose.ROTATE_90)
|
||||
|
||||
Reference in New Issue
Block a user