Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80738d1254 | ||
|
|
c54ae438c1 | ||
|
|
f33523259a | ||
|
|
96e0eab9d2 |
@@ -1,25 +1,32 @@
|
|||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from .assemblicon.context import Context
|
from .assemblicon.context import Prerequisite, Context, AdvancedContext
|
||||||
from .assemblicon.utils import setup_logging
|
from .assemblicon.utils import setup_logging
|
||||||
from .std_icons import build_standard_icons
|
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:
|
def main() -> None:
|
||||||
|
opts = parse()
|
||||||
|
|
||||||
setup_logging()
|
setup_logging()
|
||||||
|
|
||||||
repository_root = Path(__file__).resolve().parent.parent.parent.parent
|
repository_root = Path(__file__).resolve().parent.parent.parent.parent
|
||||||
iconset_input = repository_root / "src"
|
iconset_input = repository_root / "src"
|
||||||
iconset_output = repository_root / "artifact"
|
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:
|
try:
|
||||||
_build_icons(ctx)
|
_build_icons(advctx)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
logging.fatal("Runtime error: %s", e)
|
logging.fatal("Runtime error: %s", e)
|
||||||
|
|
||||||
|
|
||||||
def _build_icons(ctx: Context) -> None:
|
def _build_icons(ctx: AdvancedContext) -> None:
|
||||||
build_standard_icons(ctx)
|
build_standard_icons(ctx)
|
||||||
#build_ext_icons(ctx)
|
build_non_standard_icons(ctx)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import PIL.Image
|
import PIL.Image
|
||||||
from .utils import Artifact, ArtifactFile
|
from .utils import Artifact, ArtifactFile
|
||||||
@@ -23,3 +24,7 @@ def load_artifact(p: Path) -> ArtifactFile:
|
|||||||
def save_artifact(art: Artifact, p: Path) -> None:
|
def save_artifact(art: Artifact, p: Path) -> None:
|
||||||
logging.info("Saving artifact: %s", p)
|
logging.info("Saving artifact: %s", p)
|
||||||
art.save(p, format="PNG")
|
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_SVG_CONFIG = artrender.SvgConfig(VANILLA_ARTIFACT_HW, VANILLA_ARTIFACT_HW)
|
||||||
_DEFAULT_BLD_CONFIG = artrender.BlenderConfig(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.
|
# 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)
|
# _FD_THUMBNAIL_HWS: tuple[int, ...] = (16, 32, 48, 64, 128, 256)
|
||||||
|
|
||||||
|
|
||||||
@@ -112,7 +112,30 @@ class AdvancedContext:
|
|||||||
def __init__(self, ctx: Context) -> None:
|
def __init__(self, ctx: Context) -> None:
|
||||||
self.__context = ctx
|
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":
|
def __enter__(self) -> "AdvancedContext":
|
||||||
return self
|
return self
|
||||||
@@ -207,7 +230,10 @@ class AdvancedContext:
|
|||||||
self.__intern_render_svg(src, dst, cfg)
|
self.__intern_render_svg(src, dst, cfg)
|
||||||
|
|
||||||
def render_svg_then_load(
|
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:
|
) -> Artifact:
|
||||||
"""
|
"""
|
||||||
Render given SVG to PNG file, then load it directly.
|
Render given SVG to PNG file, then load it directly.
|
||||||
@@ -248,7 +274,10 @@ class AdvancedContext:
|
|||||||
self.__intern_render_blender(src, dst, cfg)
|
self.__intern_render_blender(src, dst, cfg)
|
||||||
|
|
||||||
def render_blender_then_load(
|
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:
|
) -> Artifact:
|
||||||
"""
|
"""
|
||||||
Render given Blender composition to PNG file, then load it directly.
|
Render given Blender composition to PNG file, then load it directly.
|
||||||
@@ -285,6 +314,15 @@ class AdvancedContext:
|
|||||||
dst = self.__fd_artifact(hw, kind, name)
|
dst = self.__fd_artifact(hw, kind, name)
|
||||||
artio.save_artifact(thumbnail, dst)
|
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:
|
def __win_artifact(self, kind: WinCategory, name: str) -> Path:
|
||||||
return self.__context.output_artifact(_ART_WIN, str(kind), f"{name}.ico")
|
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))
|
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:
|
def __mac_artifact(self, kind: MacCategory, name: str) -> Path:
|
||||||
return self.__context.output_artifact(_ART_MAC, str(kind), f"{name}.icns")
|
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)
|
logging.info("Saving macOS-only artifact with kind %s and name %s.", kind, name)
|
||||||
artrender.render_icns(art, self.__mac_artifact(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
|
# 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:
|
def build_non_standard_icons(ctx: AdvancedContext) -> None:
|
||||||
pass
|
build_mimetype_icons(ctx)
|
||||||
|
|||||||
+17
-13
@@ -1,7 +1,6 @@
|
|||||||
import PIL.Image
|
import PIL.Image
|
||||||
import PIL.ImageEnhance
|
import PIL.ImageEnhance
|
||||||
from ..assemblicon.artrender import render_svg, render_ico, SvgConfig
|
from ..assemblicon.context import AdvancedContext, FdContext, WinCategory, MacCategory
|
||||||
from ..assemblicon.context import Context
|
|
||||||
from ..assemblicon.utils import Artifact
|
from ..assemblicon.utils import Artifact
|
||||||
from ..assemblicon.geometry import MinMaxRect, PosSizeRect
|
from ..assemblicon.geometry import MinMaxRect, PosSizeRect
|
||||||
from ..assemblicon.artio import load_input_artifact, save_artifact
|
from ..assemblicon.artio import load_input_artifact, save_artifact
|
||||||
@@ -11,23 +10,26 @@ from ..assemblicon.artproc import (
|
|||||||
HorizontalAnchor,
|
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_MINMAX = MinMaxRect(20 * 4, 52 * 4, 236 * 4, 204 * 4)
|
||||||
IMAGE_INNER_RECT_POSSIZE = IMAGE_INNER_RECT_MINMAX.to_pos_size_rect()
|
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
|
# build image base
|
||||||
image_base = render_svg(
|
image_base = ctx.render_svg_then_load(
|
||||||
ctx.input_artifact("component", "image-base.svg"),
|
ctx.input_artifact("component", "image-base.svg"),
|
||||||
ctx.temporary_artifact("component", "image-base.png"),
|
|
||||||
SvgConfig(1024, 1024),
|
|
||||||
)
|
)
|
||||||
# load image base
|
# load image base
|
||||||
with image_base:
|
with image_base:
|
||||||
_build_jpg_icon(ctx, 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 = base.copy()
|
||||||
|
|
||||||
jpg_image_inner = load_input_artifact(
|
jpg_image_inner = load_input_artifact(
|
||||||
@@ -58,10 +60,12 @@ def _build_jpg_icon(ctx: Context, base: Artifact) -> None:
|
|||||||
jpg_image.paste(
|
jpg_image.paste(
|
||||||
bestfit_jpg_image_inner, IMAGE_INNER_RECT_POSSIZE.to_pillow_tuple()
|
bestfit_jpg_image_inner, IMAGE_INNER_RECT_POSSIZE.to_pillow_tuple()
|
||||||
)
|
)
|
||||||
|
|
||||||
# build artifacts
|
# build artifacts
|
||||||
save_artifact(jpg_image, ctx.temporary_artifact("ext", "jpg-image.png"))
|
# save for FD
|
||||||
render_ico(
|
ctx.save_fd_artifact(jpg_image, FdContext.MimeTypes, "image-jpeg")
|
||||||
ctx,
|
# use image/jpeg as the default image icon
|
||||||
jpg_image,
|
ctx.dup_fd_artifact(FdContext.MimeTypes, "image-jpeg", FdContext.MimeTypes, "image-x-generic")
|
||||||
ctx.output_artifact("ext", "jpg-image.ico"),
|
# 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
|
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)
|
build_action_icons(ctx)
|
||||||
|
|||||||
@@ -1,33 +1,23 @@
|
|||||||
from pathlib import Path
|
|
||||||
import PIL.Image
|
import PIL.Image
|
||||||
from ..assemblicon.artrender import render_svg, SvgConfig
|
from ..assemblicon.context import AdvancedContext, FdContext
|
||||||
from ..assemblicon.context import Context
|
|
||||||
from ..assemblicon.utils import Artifact
|
|
||||||
from ..assemblicon.artio import save_artifact
|
|
||||||
|
|
||||||
|
|
||||||
def build_action_icons(ctx: Context) -> None:
|
def build_action_icons(ctx: AdvancedContext) -> None:
|
||||||
_build_go_icons(ctx)
|
_build_go_icons(ctx)
|
||||||
|
|
||||||
|
|
||||||
def _build_go_icons(ctx: Context) -> None:
|
def _build_go_icons(ctx: AdvancedContext) -> None:
|
||||||
# build go-* base
|
# build go-* base
|
||||||
go_base = render_svg(
|
go_base = ctx.render_svg_then_load(
|
||||||
ctx.input_artifact("component", "go-base.svg"),
|
ctx.input_artifact("component", "go-base.svg")
|
||||||
ctx.temporary_artifact("component", "go-base.png"),
|
|
||||||
SvgConfig(1024, 1024),
|
|
||||||
)
|
)
|
||||||
# build go-* shining
|
# 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.input_artifact("component", "go-inner-shining.svg"),
|
||||||
ctx.temporary_artifact("component", "go-inner-shining.png"),
|
|
||||||
SvgConfig(1024, 1024),
|
|
||||||
)
|
)
|
||||||
# build go-* inner
|
# build go-* inner
|
||||||
go_inner = render_svg(
|
go_inner = ctx.render_svg_then_load(
|
||||||
ctx.input_artifact("component", "go-inner.svg"),
|
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:
|
with go_base, go_inner_shining, go_inner:
|
||||||
@@ -36,8 +26,9 @@ def _build_go_icons(ctx: Context) -> None:
|
|||||||
go = go_base.copy()
|
go = go_base.copy()
|
||||||
# render shining with inner mask
|
# render shining with inner mask
|
||||||
go.paste(go_inner_shining, (0, 0), go_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
|
# rotate it for next calling
|
||||||
go_mask = go_mask.transpose(PIL.Image.Transpose.ROTATE_90)
|
go_mask = go_mask.transpose(PIL.Image.Transpose.ROTATE_90)
|
||||||
|
|||||||
Reference in New Issue
Block a user