feat: add go icon support
This commit is contained in:
@@ -2,8 +2,8 @@ import logging
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from .assemblicon.context import Context
|
from .assemblicon.context import Context
|
||||||
from .assemblicon.utils import setup_logging
|
from .assemblicon.utils import setup_logging
|
||||||
from .image_icons import build_image_icons
|
|
||||||
from .std_icons import build_standard_icons
|
from .std_icons import build_standard_icons
|
||||||
|
from .ext_icons import build_ext_icons
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
@@ -22,4 +22,4 @@ def main() -> None:
|
|||||||
|
|
||||||
def _build_icons(ctx: Context) -> None:
|
def _build_icons(ctx: Context) -> None:
|
||||||
build_standard_icons(ctx)
|
build_standard_icons(ctx)
|
||||||
#build_image_icons(ctx)
|
#build_ext_icons(ctx)
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import PIL.Image
|
import PIL.Image
|
||||||
|
import PIL.ImageFile
|
||||||
|
|
||||||
|
|
||||||
def load_artifact(p: Path) -> PIL.Image.ImageFile.ImageFile:
|
def load_asset(p: Path) -> PIL.ImageFile.ImageFile:
|
||||||
|
logging.info("Loading asset: %s", p)
|
||||||
|
return PIL.Image.open(p, "r", ["PNG", "JPEG", "BMP"])
|
||||||
|
|
||||||
|
|
||||||
|
def load_artifact(p: Path) -> PIL.ImageFile.ImageFile:
|
||||||
|
logging.info("Loading artifact: %s", p)
|
||||||
return PIL.Image.open(p, "r", ["PNG"])
|
return PIL.Image.open(p, "r", ["PNG"])
|
||||||
|
|
||||||
|
|
||||||
def save_artifact(art: PIL.Image.Image, p: Path) -> None:
|
def save_artifact(art: PIL.Image.Image, p: Path) -> None:
|
||||||
|
logging.info("Saving artifact: %s", p)
|
||||||
art.save(p, format="PNG")
|
art.save(p, format="PNG")
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
import PIL.Image
|
import PIL.Image
|
||||||
|
import PIL.ImageFile
|
||||||
from .context import Context
|
from .context import Context
|
||||||
from .utils import Artifact
|
from .utils import Artifact
|
||||||
|
from .artio import load_artifact
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -25,8 +25,12 @@ class InkscapeConfig:
|
|||||||
f"The image height in Inkscape config must be a positive integer"
|
f"The image height in Inkscape config must be a positive integer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Add "resvg" alternative for Inkscape
|
||||||
|
# because Inkscape is too slow.
|
||||||
|
|
||||||
def inkscape_render(src: Path, dst: Path, cfg: InkscapeConfig) -> None:
|
def inkscape_render(
|
||||||
|
src: Path, dst: Path, cfg: InkscapeConfig
|
||||||
|
) -> PIL.ImageFile.ImageFile:
|
||||||
logging.info("Rendering Inkscape artifact: %s -> %s", src, dst)
|
logging.info("Rendering Inkscape artifact: %s -> %s", src, dst)
|
||||||
|
|
||||||
inkscape_bin = os.getenv("ASSEMBLICON_INKSCAPE", "inkscape")
|
inkscape_bin = os.getenv("ASSEMBLICON_INKSCAPE", "inkscape")
|
||||||
@@ -55,6 +59,8 @@ def inkscape_render(src: Path, dst: Path, cfg: InkscapeConfig) -> None:
|
|||||||
f"Fail to execute Inkscape. Return code is {proc.returncode}"
|
f"Fail to execute Inkscape. Return code is {proc.returncode}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return load_artifact(dst)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class BlenderConfig:
|
class BlenderConfig:
|
||||||
@@ -96,9 +102,11 @@ except BaseException:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def blender_render(ctx: Context, src: Path, dst: Path, cfg: BlenderConfig) -> None:
|
def blender_render(
|
||||||
|
ctx: Context, src: Path, dst: Path, cfg: BlenderConfig
|
||||||
|
) -> PIL.ImageFile.ImageFile:
|
||||||
logging.info("Rendering Blender artifact: %s -> %s", src, dst)
|
logging.info("Rendering Blender artifact: %s -> %s", src, dst)
|
||||||
|
|
||||||
script = _BLENDER_RENDER_SCRIPT.format(
|
script = _BLENDER_RENDER_SCRIPT.format(
|
||||||
width=cfg.width, height=cfg.height, dst=repr(str(dst))
|
width=cfg.width, height=cfg.height, dst=repr(str(dst))
|
||||||
)
|
)
|
||||||
@@ -115,14 +123,14 @@ def blender_render(ctx: Context, src: Path, dst: Path, cfg: BlenderConfig) -> No
|
|||||||
]
|
]
|
||||||
proc = subprocess.run(cmd, capture_output=False)
|
proc = subprocess.run(cmd, capture_output=False)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"Fail to execute Blender. Return code is {proc.returncode}")
|
||||||
f"Fail to execute Blender. Return code is {proc.returncode}"
|
|
||||||
)
|
|
||||||
if not dst.exists():
|
if not dst.exists():
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Blender exited successfully but output file {dst} is missing"
|
f"Blender exited successfully but output file {dst} is missing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return load_artifact(dst)
|
||||||
|
|
||||||
|
|
||||||
_ICON_ART_SIZE = 1024
|
_ICON_ART_SIZE = 1024
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from ..assemblicon.context import Context
|
||||||
|
from .image_icons import build_image_icons
|
||||||
|
|
||||||
|
|
||||||
|
def build_ext_icons(ctx: Context) -> None:
|
||||||
|
build_image_icons(ctx)
|
||||||
+12
-12
@@ -1,10 +1,11 @@
|
|||||||
import PIL.Image
|
import PIL.Image
|
||||||
import PIL.ImageEnhance
|
import PIL.ImageEnhance
|
||||||
from .assemblicon.render import inkscape_render, ico_render, InkscapeConfig
|
from ..assemblicon.render import inkscape_render, ico_render, InkscapeConfig
|
||||||
from .assemblicon.context import Context
|
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.artproc import (
|
from ..assemblicon.artio import load_asset, save_artifact
|
||||||
|
from ..assemblicon.artproc import (
|
||||||
aspect_ratio_scale_and_crop,
|
aspect_ratio_scale_and_crop,
|
||||||
VerticalAnchor,
|
VerticalAnchor,
|
||||||
HorizontalAnchor,
|
HorizontalAnchor,
|
||||||
@@ -16,24 +17,23 @@ IMAGE_INNER_RECT_POSSIZE = IMAGE_INNER_RECT_MINMAX.to_pos_size_rect()
|
|||||||
|
|
||||||
def build_image_icons(ctx: Context) -> None:
|
def build_image_icons(ctx: Context) -> None:
|
||||||
# build image base
|
# build image base
|
||||||
inkscape_render(
|
image_base = inkscape_render(
|
||||||
ctx.input_artifact("component", "image-base.svg"),
|
ctx.input_artifact("component", "image-base.svg"),
|
||||||
ctx.temporary_artifact("component", "image-base.png"),
|
ctx.temporary_artifact("component", "image-base.png"),
|
||||||
InkscapeConfig(1024, 1024),
|
InkscapeConfig(1024, 1024),
|
||||||
)
|
)
|
||||||
# load image base
|
# load image base
|
||||||
with PIL.Image.open(
|
with image_base:
|
||||||
ctx.temporary_artifact("component", "image-base.png")
|
|
||||||
) as 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: Context, base: Artifact) -> None:
|
||||||
jpg_image = base.copy()
|
jpg_image = base.copy()
|
||||||
|
|
||||||
with PIL.Image.open(
|
jpg_image_inner = load_asset(
|
||||||
ctx.input_artifact("ext", "bitmap", "Niinsaare_järv.jpg")
|
ctx.input_artifact("ext", "bitmap", "Niinsaare_järv.jpg")
|
||||||
) as jpg_image_inner:
|
)
|
||||||
|
with jpg_image_inner:
|
||||||
# crop the area which is interested by ourselves
|
# crop the area which is interested by ourselves
|
||||||
interest_area = PosSizeRect(2700, 0, 5016, 3888).to_min_max_rect()
|
interest_area = PosSizeRect(2700, 0, 5016, 3888).to_min_max_rect()
|
||||||
crop_jpg_image_inner = jpg_image_inner.crop(interest_area.to_pillow_tuple())
|
crop_jpg_image_inner = jpg_image_inner.crop(interest_area.to_pillow_tuple())
|
||||||
@@ -59,7 +59,7 @@ def _build_jpg_icon(ctx: Context, base: Artifact) -> None:
|
|||||||
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
|
||||||
jpg_image.save(ctx.temporary_artifact("ext", "jpg-image.png"))
|
save_artifact(jpg_image, ctx.temporary_artifact("ext", "jpg-image.png"))
|
||||||
ico_render(
|
ico_render(
|
||||||
ctx,
|
ctx,
|
||||||
jpg_image,
|
jpg_image,
|
||||||
@@ -1,14 +1,9 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import PIL.Image
|
import PIL.Image
|
||||||
from ..assemblicon.render import inkscape_render, ico_render, InkscapeConfig
|
from ..assemblicon.render import inkscape_render, InkscapeConfig
|
||||||
from ..assemblicon.context import Context
|
from ..assemblicon.context import Context
|
||||||
from ..assemblicon.utils import Artifact
|
from ..assemblicon.utils import Artifact
|
||||||
from ..assemblicon.geometry import MinMaxRect, PosSizeRect
|
from ..assemblicon.artio import save_artifact
|
||||||
from ..assemblicon.artproc import (
|
|
||||||
aspect_ratio_scale_and_crop,
|
|
||||||
VerticalAnchor,
|
|
||||||
HorizontalAnchor,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def build_action_icons(ctx: Context) -> None:
|
def build_action_icons(ctx: Context) -> None:
|
||||||
@@ -17,27 +12,44 @@ def build_action_icons(ctx: Context) -> None:
|
|||||||
|
|
||||||
def _build_go_icons(ctx: Context) -> None:
|
def _build_go_icons(ctx: Context) -> None:
|
||||||
# build go-* base
|
# build go-* base
|
||||||
inkscape_render(
|
go_base = inkscape_render(
|
||||||
ctx.input_artifact("component", "go-base.svg"),
|
ctx.input_artifact("component", "go-base.svg"),
|
||||||
ctx.temporary_artifact("component", "go-base.png"),
|
ctx.temporary_artifact("component", "go-base.png"),
|
||||||
InkscapeConfig(1024, 1024),
|
InkscapeConfig(1024, 1024),
|
||||||
)
|
)
|
||||||
# build go-* shining
|
# build go-* shining
|
||||||
inkscape_render(
|
go_shining = inkscape_render(
|
||||||
ctx.input_artifact("component", "go-inner-shining.svg"),
|
ctx.input_artifact("component", "go-inner-shining.svg"),
|
||||||
ctx.temporary_artifact("component", "go-inner-shining.png"),
|
ctx.temporary_artifact("component", "go-inner-shining.png"),
|
||||||
InkscapeConfig(1024, 1024),
|
InkscapeConfig(1024, 1024),
|
||||||
)
|
)
|
||||||
|
|
||||||
with PIL.Image.open(ctx.temporary_artifact("component", "go-base.png")) as go_base:
|
with go_base, go_shining:
|
||||||
with PIL.Image.open(
|
_build_go_icon(
|
||||||
ctx.temporary_artifact("component", "go-inner-shining.png")
|
ctx,
|
||||||
) as go_shining:
|
go_base,
|
||||||
_build_go_icon(ctx, go_base, go_shining, ctx.input_artifact("go-previous.svg"))
|
go_shining,
|
||||||
_build_go_icon(ctx, go_base, go_shining, ctx.input_artifact("go-next.svg"))
|
ctx.input_artifact("go-previous.svg"),
|
||||||
|
ctx.temporary_artifact("go-previous.png"),
|
||||||
|
ctx.output_artifact("go-previous.png")
|
||||||
|
)
|
||||||
|
_build_go_icon(
|
||||||
|
ctx,
|
||||||
|
go_base,
|
||||||
|
go_shining,
|
||||||
|
ctx.input_artifact("go-next.svg"),
|
||||||
|
ctx.temporary_artifact("go-next.png"),
|
||||||
|
ctx.output_artifact("go-next.png")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _build_go_icon(ctx: Context, base: Artifact, shining: Artifact, mask: Path) -> None:
|
def _build_go_icon(
|
||||||
|
ctx: Context, base: Artifact, shining: Artifact, mask: Path, mask_dst: Path, dst: Path
|
||||||
|
) -> None:
|
||||||
go = base.copy()
|
go = base.copy()
|
||||||
|
# render shining with mask
|
||||||
|
go_mask = inkscape_render(mask, mask_dst, InkscapeConfig(1024, 1024))
|
||||||
|
go.paste(shining, (0, 0), go_mask)
|
||||||
|
# save as image
|
||||||
|
save_artifact(go, dst)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user