Compare commits
31
Commits
80738d1254
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a951c6d11 | ||
|
|
890019bc54 | ||
|
|
0d43fe3962 | ||
|
|
a33c3538f5 | ||
|
|
72edad6edc | ||
|
|
2015ebf925 | ||
|
|
1e15fb4783 | ||
|
|
42a2b08abf | ||
|
|
61e003c741 | ||
|
|
7b216b8865 | ||
|
|
36adf8029a | ||
|
|
e0d6aa63e6 | ||
|
|
765375f04c | ||
|
|
a563917aa8 | ||
|
|
bb5032d502 | ||
|
|
db04b9c809 | ||
|
|
44ba5fbbee | ||
|
|
f650d3f98a | ||
|
|
43e3bd39ef | ||
|
|
49edad7d33 | ||
|
|
28fa01992e | ||
|
|
d13f18cc90 | ||
|
|
da52ab5028 | ||
|
|
988a9fc04f | ||
|
|
63ba6d44f7 | ||
|
|
bcac59ceb1 | ||
|
|
54af04a48f | ||
|
|
e43029ea47 | ||
|
|
3a9a6d99cb | ||
|
|
892a946998 | ||
|
|
9d20e60adb |
+14
@@ -0,0 +1,14 @@
|
||||
# License
|
||||
|
||||
This project has mixed licencing.
|
||||
You are free to copy, redistribute and/or modify aspects of this work under the terms of each licence accordingly.
|
||||
|
||||
## Icon Set Builder
|
||||
|
||||
The builder of this icon set is under **MIT License**.
|
||||
The content of these part is under `tool` directory.
|
||||
|
||||
## Icon Set Assets
|
||||
|
||||
The assets for generating this icon set is under different licenses.
|
||||
This project follows the [REUSE Specification](https://reuse.software/). You can collect the licensing information using the REUSE tool, or browse the `REUSE.toml` files located in their directory manually.
|
||||
@@ -5,4 +5,12 @@ Yet Another Aero Icon Set.
|
||||
## Repository Notes
|
||||
|
||||
The content submitted in Git repository doesn't include any binary assets.
|
||||
It only includes code part of this icon set for tracing the change of build code.
|
||||
It only includes the code part of this repository for tracing the changes of code building this icon set.
|
||||
|
||||
## Status
|
||||
|
||||
Work in progress...
|
||||
|
||||
## License
|
||||
|
||||
See [LICENSES](LICENSE.md) for more details.
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
Ivar Leidus, CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0>, via Wikimedia Commons
|
||||
https://commons.wikimedia.org/wiki/File:Niinsaare_j%C3%A4rv.jpg
|
||||
|
||||
Pascalou petit, CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0>, via Wikimedia Commons
|
||||
https://commons.wikimedia.org/wiki/File:Aster_Tataricus.JPG
|
||||
|
||||
https://commons.wikimedia.org/wiki/File:Great_pershing_balloon_derby_2005_09_04.jpg
|
||||
Balloon launch at the Great Pershing Balloon Derby near Brookfield, Missouri on September 4, 2005. Photo taken by Joe DeShon.
|
||||
This file is licensed under the Creative Commons Attribution 2.5 Generic license.
|
||||
|
||||
https://commons.wikimedia.org/wiki/File:Wild_Petunia_Blue_Flower_1.JPG
|
||||
I, Jonathan Zander, CC BY-SA 3.0 <http://creativecommons.org/licenses/by-sa/3.0/>, via Wikimedia Commons
|
||||
|
||||
https://commons.wikimedia.org/wiki/File:Daisy_(Argyranthemum_frutescens).jpg
|
||||
Fir0002, CC BY-SA 3.0 <http://creativecommons.org/licenses/by-sa/3.0/>, via Wikimedia Commons
|
||||
@@ -0,0 +1,8 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "Nycticorax_nycticorax12.jpg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://commons.wikimedia.org/wiki/File:Nycticorax_nycticorax12.jpg"
|
||||
SPDX-FileCopyrightText = "Calibas"
|
||||
SPDX-License-Identifier = "CC-BY-SA-3.0"
|
||||
@@ -0,0 +1,75 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "go-base.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "go-inner-shining.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "go-inner.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://github.com/google/material-design-icon"
|
||||
SPDX-FileCopyrightText = ["2014-2026 Google", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "object-flip-horizontal.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://invent.kde.org/frameworks/oxygen-icons"
|
||||
SPDX-FileCopyrightText = ["2015-2026 KDE Oxygen Icon Theme Team", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
|
||||
[[annotations]]
|
||||
path = "object-flip-vertical.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://invent.kde.org/frameworks/oxygen-icons"
|
||||
SPDX-FileCopyrightText = ["2015-2026 KDE Oxygen Icon Theme Team", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
|
||||
[[annotations]]
|
||||
path = "object-rotate-left.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://invent.kde.org/frameworks/oxygen-icons"
|
||||
SPDX-FileCopyrightText = ["2015-2026 KDE Oxygen Icon Theme Team", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
|
||||
[[annotations]]
|
||||
path = "object-rotate-right.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://invent.kde.org/frameworks/oxygen-icons"
|
||||
SPDX-FileCopyrightText = ["2015-2026 KDE Oxygen Icon Theme Team", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
|
||||
[[annotations]]
|
||||
path = "image-png-checkerboard.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "dialog-infomation.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://invent.kde.org/frameworks/oxygen-icons"
|
||||
SPDX-FileCopyrightText = ["2015-2026 KDE Oxygen Icon Theme Team", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
|
||||
[[annotations]]
|
||||
path = "dialog-warning.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://invent.kde.org/frameworks/oxygen-icons"
|
||||
SPDX-FileCopyrightText = ["2015-2026 KDE Oxygen Icon Theme Team", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
|
||||
[[annotations]]
|
||||
path = "dialog-error.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://invent.kde.org/frameworks/oxygen-icons"
|
||||
SPDX-FileCopyrightText = "2015-2026 KDE Oxygen Icon Theme Team"
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
@@ -0,0 +1,13 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "sarasacw-picture-frame.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "notepad.blend"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
@@ -0,0 +1,29 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "Niinsaare_järv.jpg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://commons.wikimedia.org/wiki/File:Niinsaare_j%C3%A4rv.jpg"
|
||||
SPDX-FileCopyrightText = "2013 Ivar Leidus"
|
||||
SPDX-License-Identifier = "CC-BY-SA-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "Tulipa_suaveolens_floriade_to_Canberra.jpg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://commons.wikimedia.org/wiki/File:Tulipa_suaveolens_floriade_to_Canberra.jpg"
|
||||
SPDX-FileCopyrightText = "2005 John O'Neill"
|
||||
SPDX-License-Identifier = "CC-BY-SA-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "Hot-air_balloon_in_Tambov_-_02.jpg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://commons.wikimedia.org/wiki/File:Hot-air_balloon_in_Tambov_-_02.jpg"
|
||||
SPDX-FileCopyrightText = "2022 Alexander Novikov"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://commons.wikimedia.org/wiki/File:Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg"
|
||||
SPDX-FileCopyrightText = ["1889 Vincent van Gogh", "Google Arts & Culture"]
|
||||
SPDX-License-Identifier = "CC0-1.0" # Public Domain actually.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
@@ -0,0 +1,5 @@
|
||||
Blue Background Node 1,#001fbe
|
||||
Blue Background Node 2,#1439ff
|
||||
|
||||
Paper Background Node 1,#ffffff
|
||||
Paper Backgroundr Node 2,#e3e3e3
|
||||
|
@@ -0,0 +1,40 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "image-base.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "generic-background.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "triangle.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://github.com/Templarian/MaterialDesign"
|
||||
SPDX-FileCopyrightText = ["2014-2025 Austin Andrews", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "magnifying-glass.blend"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 yyc12345"
|
||||
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "minus.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://github.com/google/material-design-icon"
|
||||
SPDX-FileCopyrightText = ["2014-2026 Google", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "plus.svg"
|
||||
precedence = "override"
|
||||
SPDX-FileComment = "Source: https://github.com/google/material-design-icon"
|
||||
SPDX-FileCopyrightText = ["2014-2026 Google", "2026 yyc12345"]
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
@@ -1,5 +0,0 @@
|
||||
[[licenses]]
|
||||
filename = 'Niinsaare_järv.jpg'
|
||||
license = "CC-BY-SA-3.0"
|
||||
author = ["Ivar Leidus", "Wikimedia Commons"]
|
||||
source = 'https://commons.wikimedia.org/wiki/File:Niinsaare_j%C3%A4rv.jpg'
|
||||
@@ -0,0 +1,7 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "**"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "2026 Sarasa's Chip Workshop"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
+4
-1
@@ -8,7 +8,7 @@ authors = [
|
||||
]
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"pillow>=12.3.0",
|
||||
"assemblicon",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
@@ -17,3 +17,6 @@ aurora-iconset-builder = "aurora_iconset_builder:main"
|
||||
[build-system]
|
||||
requires = ["uv_build>=0.8.0,<0.9"]
|
||||
build-backend = "uv_build"
|
||||
|
||||
[tool.uv.sources]
|
||||
assemblicon = { git = "https://github.com/SarasasChipWorkshop/assemblicon" }
|
||||
|
||||
@@ -1,32 +1,44 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from .assemblicon.context import Prerequisite, Context, AdvancedContext
|
||||
from .assemblicon.utils import setup_logging
|
||||
from .std_icons import build_standard_icons
|
||||
from .nostd_icons import build_non_standard_icons
|
||||
from assemblicon.highlevel.utils import DEFAULT_FD_THUMBNAIL_HWS
|
||||
from assemblicon.highlevel.environment import Environment
|
||||
from assemblicon.highlevel.context import Context
|
||||
from assemblicon.logger import APP_LOGGER as LOGGER
|
||||
from .cli import parse
|
||||
from .types import AuroraPrologue, AuroraContext
|
||||
from . import std_icons, nostd_icons
|
||||
|
||||
|
||||
def main() -> None:
|
||||
opts = parse()
|
||||
|
||||
setup_logging()
|
||||
def tempdir_initializer(p: Path) -> None:
|
||||
# create our special temporary subdirectory
|
||||
comp = p / "component"
|
||||
comp.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
repository_root = Path(__file__).resolve().parent.parent.parent.parent
|
||||
iconset_input = repository_root / "src"
|
||||
iconset_output = repository_root / "artifact"
|
||||
prereq = Prerequisite(
|
||||
iconset_input, iconset_output, opts.svg_render.to_assemblicon_type()
|
||||
prologue = AuroraPrologue(
|
||||
iconset_input,
|
||||
iconset_output,
|
||||
opts.svg_render,
|
||||
# TODO: For easy testing, we only build 32x32 and 48x48.
|
||||
# Enable full generation after testing.
|
||||
# DEFAULT_FD_THUMBNAIL_HWS,
|
||||
(32, 48, 256),
|
||||
tempdir_initializer,
|
||||
)
|
||||
ctx = Context(prereq)
|
||||
advctx = AdvancedContext(ctx)
|
||||
env = Environment(prologue)
|
||||
ctx = Context(env)
|
||||
|
||||
try:
|
||||
_build_icons(advctx)
|
||||
register(ctx)
|
||||
ctx.run(opts.selection)
|
||||
except BaseException as e:
|
||||
logging.fatal("Runtime error: %s", e)
|
||||
LOGGER.fatal("Runtime error: %s", e)
|
||||
|
||||
|
||||
def _build_icons(ctx: AdvancedContext) -> None:
|
||||
build_standard_icons(ctx)
|
||||
build_non_standard_icons(ctx)
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
std_icons.register(ctx)
|
||||
nostd_icons.register(ctx)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import logging
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import PIL.Image
|
||||
from .utils import Artifact, ArtifactFile
|
||||
|
||||
|
||||
def load_input_artifact(p: Path) -> ArtifactFile:
|
||||
"""
|
||||
Load input artifact used for building temporary and output artifact.
|
||||
"""
|
||||
logging.info("Loading asset: %s", p)
|
||||
return PIL.Image.open(p, "r", ["PNG", "JPEG", "BMP"])
|
||||
|
||||
|
||||
def load_artifact(p: Path) -> ArtifactFile:
|
||||
"""
|
||||
Load artifact saved previously as the intermediary.
|
||||
"""
|
||||
logging.info("Loading artifact: %s", p)
|
||||
return PIL.Image.open(p, "r", ["PNG"])
|
||||
|
||||
|
||||
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)
|
||||
@@ -1,58 +0,0 @@
|
||||
import enum
|
||||
import math
|
||||
from .utils import Artifact
|
||||
|
||||
|
||||
class HorizontalAnchor(enum.IntEnum):
|
||||
Left = enum.auto()
|
||||
Center = enum.auto()
|
||||
Right = enum.auto()
|
||||
|
||||
|
||||
class VerticalAnchor(enum.IntEnum):
|
||||
Top = enum.auto()
|
||||
Center = enum.auto()
|
||||
Bottom = enum.auto()
|
||||
|
||||
|
||||
def _anchor_offset(
|
||||
oversize: int, anchor: HorizontalAnchor | VerticalAnchor
|
||||
) -> int:
|
||||
match anchor:
|
||||
case HorizontalAnchor.Left | VerticalAnchor.Top:
|
||||
return 0
|
||||
case HorizontalAnchor.Center | VerticalAnchor.Center:
|
||||
return oversize // 2
|
||||
case HorizontalAnchor.Right | VerticalAnchor.Bottom:
|
||||
return oversize
|
||||
|
||||
|
||||
def aspect_ratio_scale_and_crop(
|
||||
art: Artifact,
|
||||
target_width: int,
|
||||
target_height: int,
|
||||
scale_resample: int,
|
||||
crop_horizontal_anchor: HorizontalAnchor,
|
||||
crop_vertical_anchor: VerticalAnchor,
|
||||
) -> Artifact:
|
||||
if target_width <= 0:
|
||||
raise ValueError("Target width must be a positive integer")
|
||||
if target_height <= 0:
|
||||
raise ValueError("Target height must be positive integer")
|
||||
|
||||
scale = max(target_width / art.width, target_height / art.height)
|
||||
# use math.ceil to ensure that resized image at least has required size
|
||||
# (floating point value error may cause this)
|
||||
scaled_width = math.ceil(art.width * scale)
|
||||
scaled_height = math.ceil(art.height * scale)
|
||||
scaled = art.resize((scaled_width, scaled_height), scale_resample)
|
||||
|
||||
crop_x = _anchor_offset(
|
||||
scaled_width - target_width, crop_horizontal_anchor
|
||||
)
|
||||
crop_y = _anchor_offset(
|
||||
scaled_height - target_height, crop_vertical_anchor
|
||||
)
|
||||
return scaled.crop(
|
||||
(crop_x, crop_y, crop_x + target_width, crop_y + target_height)
|
||||
)
|
||||
@@ -1,211 +0,0 @@
|
||||
import logging
|
||||
import os
|
||||
import enum
|
||||
import subprocess
|
||||
from typing import Iterable, Iterator
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass
|
||||
import PIL.Image
|
||||
from .utils import Artifact, check_vanilla_artifact
|
||||
|
||||
|
||||
class SvgRenderKind(enum.IntEnum):
|
||||
Inkscape = enum.auto()
|
||||
ReSvg = enum.auto()
|
||||
|
||||
|
||||
@dataclass
|
||||
class SvgConfig:
|
||||
width: int
|
||||
height: int
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.width <= 0:
|
||||
raise ValueError(
|
||||
f"The image width in Inkscape config must be a positive integer"
|
||||
)
|
||||
if self.height <= 0:
|
||||
raise ValueError(
|
||||
f"The image height in Inkscape config must be a positive integer"
|
||||
)
|
||||
|
||||
|
||||
def render_svg(src: Path, dst: Path, kind: SvgRenderKind, cfg: SvgConfig) -> None:
|
||||
"""
|
||||
Render given SVG file to PNG file.
|
||||
|
||||
:param src: The path to SVG file to be rendered
|
||||
:param dst: The path to rendered PNG file.
|
||||
:param kind: The selected SVG render kind.
|
||||
:param cfg: The configuration when rendering.
|
||||
"""
|
||||
logging.info("Rendering SVG artifact with render {kind.name}: %s -> %s", src, dst)
|
||||
|
||||
match kind:
|
||||
case SvgRenderKind.Inkscape:
|
||||
inkscape_bin = os.getenv("ASSEMBLICON_INKSCAPE", "inkscape")
|
||||
cmd = [
|
||||
inkscape_bin,
|
||||
"--export-area-page",
|
||||
"--export-width",
|
||||
str(cfg.width),
|
||||
"--export-height",
|
||||
str(cfg.height),
|
||||
"--export-type",
|
||||
"png",
|
||||
"--export-png-color-mode",
|
||||
"RGBA_8",
|
||||
"--export-background-opacity",
|
||||
"0.0",
|
||||
"--export-png-use-dithering",
|
||||
"false",
|
||||
"--export-filename",
|
||||
str(dst),
|
||||
str(src),
|
||||
]
|
||||
case SvgRenderKind.ReSvg:
|
||||
resvg_bin = os.getenv("ASSEMBLICON_RESVG", "resvg")
|
||||
cmd = [
|
||||
resvg_bin,
|
||||
"--width",
|
||||
str(cfg.width),
|
||||
"--height",
|
||||
str(cfg.height),
|
||||
str(src),
|
||||
str(dst),
|
||||
]
|
||||
|
||||
proc = subprocess.run(cmd, capture_output=False)
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(
|
||||
f"Fail to execute SVG render {kind.name}. "
|
||||
f"Return code is {proc.returncode}"
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class BlenderConfig:
|
||||
width: int
|
||||
height: int
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.width <= 0:
|
||||
raise ValueError(
|
||||
f"The image width in Blender config must be a positive integer"
|
||||
)
|
||||
if self.height <= 0:
|
||||
raise ValueError(
|
||||
f"The image height in Blender config must be a positive integer"
|
||||
)
|
||||
|
||||
|
||||
_BLENDER_RENDER_SCRIPT = """\
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
try:
|
||||
import bpy
|
||||
|
||||
render = bpy.context.scene.render
|
||||
render.resolution_x = {width}
|
||||
render.resolution_y = {height}
|
||||
render.resolution_percentage = 100
|
||||
render.image_settings.file_format = "PNG"
|
||||
render.image_settings.color_mode = "RGBA"
|
||||
render.image_settings.color_depth = "8"
|
||||
render.film_transparent = True
|
||||
render.use_file_extension = False
|
||||
render.filepath = {dst}
|
||||
bpy.ops.render.render(write_still=True)
|
||||
except BaseException:
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
"""
|
||||
|
||||
|
||||
def render_blender(src: Path, dst: Path, temp_script: Path, cfg: BlenderConfig) -> None:
|
||||
"""
|
||||
Render given Blender composition into PNG file.
|
||||
|
||||
:param src: The path to Blender composition file to be rendered
|
||||
:param dst: The path to rendered PNG file.
|
||||
:param temp_script: The path to temporary Python script instructing Blender rendering.
|
||||
The caller must make sure that this file is immutable during calling this function.
|
||||
:param cfg: The configuration when rendering.
|
||||
"""
|
||||
logging.info("Rendering Blender artifact: %s -> %s", src, dst)
|
||||
|
||||
script = _BLENDER_RENDER_SCRIPT.format(
|
||||
width=cfg.width, height=cfg.height, dst=repr(str(dst))
|
||||
)
|
||||
temp_script.write_text(script, encoding="utf-8")
|
||||
|
||||
blender_bin = os.getenv("ASSEMBLICON_BLENDER", "blender")
|
||||
cmd = [
|
||||
blender_bin,
|
||||
"--background",
|
||||
str(src),
|
||||
"--python",
|
||||
str(temp_script),
|
||||
]
|
||||
proc = subprocess.run(cmd, capture_output=False)
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(f"Fail to execute Blender. Return code is {proc.returncode}")
|
||||
if not dst.exists():
|
||||
raise RuntimeError(
|
||||
f"Blender exited successfully but output file {dst} is missing"
|
||||
)
|
||||
|
||||
|
||||
def render_thumbnail(art: Artifact, hws: Iterable[int]) -> Iterator[Artifact]:
|
||||
"""
|
||||
Render given artifact as multiple resolution thumbnails.
|
||||
|
||||
:param art: The artifact to be rendered.
|
||||
:param hws: The int iterable holding all resolution of thumbnails (square thumbnail only)
|
||||
:return: A generator outputing thumbnail one by one with the order of given resolution.
|
||||
"""
|
||||
check_vanilla_artifact(art)
|
||||
for hw in hws:
|
||||
logging.info("Rendering thumbnail %dx%d.", hw, hw)
|
||||
thumbnail = art.copy()
|
||||
thumbnail.thumbnail((hw, hw), PIL.Image.Resampling.LANCZOS)
|
||||
yield thumbnail
|
||||
|
||||
|
||||
def render_ico(art: Artifact, dst: Path) -> None:
|
||||
"""
|
||||
Render given artifact as Windows ICO in given path.
|
||||
|
||||
:param art: The artifact to be rendered.
|
||||
:param dst: The path to rendered result.
|
||||
"""
|
||||
logging.info("Rendering .ICO artifact: -> %s", dst)
|
||||
|
||||
check_vanilla_artifact(art)
|
||||
sizes = [16, 32, 48, 64, 128, 256]
|
||||
# provide every frame explicitly so that we never depend on
|
||||
# undocumented plugin-side resizing behavior
|
||||
frames = list(render_thumbnail(art, sizes))
|
||||
art.save(
|
||||
dst,
|
||||
format="ICO",
|
||||
sizes=[(size, size) for size in sizes],
|
||||
append_images=frames,
|
||||
)
|
||||
|
||||
|
||||
def render_icns(art: Artifact, dst: Path) -> None:
|
||||
"""
|
||||
Render given artifact as macOS ICNS in given path.
|
||||
|
||||
:param art: The artifact to be rendered.
|
||||
:param dst: The path to rendered result.
|
||||
"""
|
||||
logging.info("Rendering .ICNS artifact: -> %s", dst)
|
||||
|
||||
check_vanilla_artifact(art)
|
||||
# provide every smaller frame explicitly; the 1024x1024 entry is
|
||||
# covered by the art itself
|
||||
frames = list(render_thumbnail(art, (512, 256, 128, 64, 32)))
|
||||
art.save(dst, format="ICNS", append_images=frames)
|
||||
@@ -1,368 +0,0 @@
|
||||
import logging
|
||||
import tempfile
|
||||
import os
|
||||
import enum
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from types import TracebackType
|
||||
from .utils import Artifact, ArtifactFile, VANILLA_ARTIFACT_HW
|
||||
from .artrender import SvgRenderKind, SvgConfig, BlenderConfig
|
||||
from . import artio, artrender
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Prerequisite:
|
||||
input_directory: Path
|
||||
output_directory: Path
|
||||
svg_render: SvgRenderKind
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not self.input_directory.is_dir():
|
||||
raise ValueError(
|
||||
f"Given input path {self.input_directory} is not existing directory."
|
||||
)
|
||||
if not self.output_directory.is_dir():
|
||||
raise ValueError(
|
||||
f"Given output path {self.output_directory} is not existing directory."
|
||||
)
|
||||
|
||||
|
||||
class Context:
|
||||
__prerequisite: Prerequisite
|
||||
__temp_dir: tempfile.TemporaryDirectory[str]
|
||||
|
||||
def __init__(self, prerequisite: Prerequisite) -> None:
|
||||
self.__prerequisite = prerequisite
|
||||
self.__temp_dir = tempfile.TemporaryDirectory()
|
||||
|
||||
@property
|
||||
def prerequisite(self) -> Prerequisite:
|
||||
return self.__prerequisite
|
||||
|
||||
def input_artifact(self, *args: str) -> Path:
|
||||
return self.__prerequisite.input_directory / Path(*args)
|
||||
|
||||
def output_artifact(self, *args: str) -> Path:
|
||||
return self.__prerequisite.output_directory / Path(*args)
|
||||
|
||||
def temporary_artifact(self, *args: str) -> Path:
|
||||
return Path(self.__temp_dir.name) / Path(*args)
|
||||
|
||||
def __enter__(self) -> "Context":
|
||||
return self
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
exc_type: type[BaseException] | None,
|
||||
exc_value: BaseException | None,
|
||||
traceback: TracebackType | None,
|
||||
) -> None:
|
||||
self.__temp_dir.cleanup()
|
||||
|
||||
|
||||
class FdContext(enum.StrEnum):
|
||||
Actions = "actions"
|
||||
Animations = "animations"
|
||||
Applications = "apps"
|
||||
Categories = "categories"
|
||||
Devices = "devices"
|
||||
Emblems = "emblems"
|
||||
Emotes = "emotes"
|
||||
International = "intl"
|
||||
MimeTypes = "mimetypes"
|
||||
Places = "places"
|
||||
Status = "status"
|
||||
|
||||
|
||||
class WinCategory(enum.StrEnum):
|
||||
Application = "apps"
|
||||
"""Icons for applications"""
|
||||
Extension = "exts"
|
||||
"""Icons for file extensions"""
|
||||
|
||||
|
||||
class MacCategory(enum.StrEnum):
|
||||
Application = "apps"
|
||||
"""Icons for applications"""
|
||||
Extension = "exts"
|
||||
"""Icons for file extensions"""
|
||||
|
||||
|
||||
_TEMP_USER_DIR: str = "user"
|
||||
_TEMP_LIB_DIR: str = "assemblicon"
|
||||
_TEMP_LIB_ALLOC_DIR: str = "alloc"
|
||||
_TEMP_LIB_STABLE_DIR: str = "stable"
|
||||
|
||||
_ART_WIN: str = "windows"
|
||||
_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 32x32 and 48x48.
|
||||
# Enable full generation after testing.
|
||||
_FD_THUMBNAIL_HWS: tuple[int, ...] = (32, 48)
|
||||
# _FD_THUMBNAIL_HWS: tuple[int, ...] = (16, 32, 48, 64, 128, 256)
|
||||
|
||||
|
||||
class AdvancedContext:
|
||||
__context: Context
|
||||
|
||||
def __init__(self, ctx: Context) -> None:
|
||||
self.__context = ctx
|
||||
|
||||
# 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
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
exc_type: type[BaseException] | None,
|
||||
exc_value: BaseException | None,
|
||||
traceback: TracebackType | None,
|
||||
) -> None:
|
||||
self.__context.__exit__(exc_type, exc_value, traceback)
|
||||
|
||||
# region: Input Artifact
|
||||
|
||||
def input_artifact(self, *args: str) -> Path:
|
||||
"""
|
||||
Get the path to input artifact.
|
||||
"""
|
||||
return self.__context.input_artifact(*args)
|
||||
|
||||
def load_input_bitmap_artifact(self, *args: str) -> ArtifactFile:
|
||||
"""
|
||||
Load given input bitmap asset.
|
||||
"""
|
||||
return artio.load_input_artifact(self.input_artifact(*args))
|
||||
|
||||
# endregion
|
||||
|
||||
# region: Temporary Artifact
|
||||
|
||||
def __user_temporary_artifact(self, *args: str) -> Path:
|
||||
return self.__context.temporary_artifact(_TEMP_USER_DIR, *args)
|
||||
|
||||
def __lib_temporary_artifact(self, *args: str) -> Path:
|
||||
return self.__context.temporary_artifact(_TEMP_LIB_DIR, *args)
|
||||
|
||||
def temporary_artifact(self, *args: str) -> Path:
|
||||
"""
|
||||
Get the path to temporary artifact.
|
||||
|
||||
All existence of sub-directory should be ensured on your own.
|
||||
"""
|
||||
return self.__user_temporary_artifact(*args)
|
||||
|
||||
def load_temporary_artifact(self, *args: str) -> ArtifactFile:
|
||||
return artio.load_artifact(self.temporary_artifact(*args))
|
||||
|
||||
def save_temporary_artifact(self, art: Artifact, *args: str) -> None:
|
||||
"""
|
||||
Save given artifact as temporary artifact.
|
||||
|
||||
All existence of sub-directory should be ensured on your own.
|
||||
"""
|
||||
artio.save_artifact(art, self.temporary_artifact(*args))
|
||||
|
||||
def __allocate_lib_temporary_artifact(self, suffix: Optional[str] = None) -> Path:
|
||||
p = self.__lib_temporary_artifact(_TEMP_LIB_ALLOC_DIR)
|
||||
(fd, pf) = tempfile.mkstemp(suffix=suffix, prefix=None, dir=str(p), text=False)
|
||||
os.close(fd)
|
||||
return Path(pf)
|
||||
|
||||
def __fetch_const_lib_temporary_artifact(self, name: str) -> Path:
|
||||
return self.__lib_temporary_artifact(_TEMP_LIB_STABLE_DIR, name)
|
||||
|
||||
# endregion
|
||||
|
||||
# region: Render Wrapper
|
||||
|
||||
def __intern_render_svg(
|
||||
self, src: Path, dst: Optional[Path], cfg: SvgConfig
|
||||
) -> Path:
|
||||
"""
|
||||
Internal used function for rendering SVG.
|
||||
|
||||
:return: The path to destination storing render result.
|
||||
"""
|
||||
if dst is None:
|
||||
dst = self.__allocate_lib_temporary_artifact(".png")
|
||||
artrender.render_svg(src, dst, self.__context.prerequisite.svg_render, cfg)
|
||||
return dst
|
||||
|
||||
def render_svg(
|
||||
self, src: Path, dst: Path, cfg: SvgConfig = _DEFAULT_SVG_CONFIG
|
||||
) -> None:
|
||||
"""
|
||||
Just render given SVG to PNG file.
|
||||
|
||||
:param src: The path to SVG file to be rendered.
|
||||
:param dst: The path to rendered PNG file.
|
||||
:param cfg: The configuration when rendering SVG file. Default for vanilla artifact.
|
||||
"""
|
||||
self.__intern_render_svg(src, dst, cfg)
|
||||
|
||||
def render_svg_then_load(
|
||||
self,
|
||||
src: Path,
|
||||
dst: Optional[Path] = None,
|
||||
cfg: SvgConfig = _DEFAULT_SVG_CONFIG,
|
||||
) -> Artifact:
|
||||
"""
|
||||
Render given SVG to PNG file, then load it directly.
|
||||
|
||||
:param src: The path to SVG file to be rendered.
|
||||
:param dst: The path to rendered PNG file.
|
||||
``None`` if you don't need to store it in temporary or output directory.
|
||||
:param cfg: The configuration when rendering SVG file. Default for vanilla artifact.
|
||||
:return: The loaded built PNG file.
|
||||
"""
|
||||
dst = self.__intern_render_svg(src, dst, cfg)
|
||||
return artio.load_artifact(dst)
|
||||
|
||||
def __intern_render_blender(
|
||||
self, src: Path, dst: Optional[Path], cfg: BlenderConfig
|
||||
) -> Path:
|
||||
"""
|
||||
Internal used function for rendering Blender composition.
|
||||
|
||||
:return: The path to destination storing render result.
|
||||
"""
|
||||
temp_script = self.__fetch_const_lib_temporary_artifact("blender.py")
|
||||
if dst is None:
|
||||
dst = self.__allocate_lib_temporary_artifact(".png")
|
||||
artrender.render_blender(src, dst, temp_script, cfg)
|
||||
return dst
|
||||
|
||||
def render_blender(
|
||||
self, src: Path, dst: Path, cfg: BlenderConfig = _DEFAULT_BLD_CONFIG
|
||||
) -> None:
|
||||
"""
|
||||
Just render given Blender composition to PNG file.
|
||||
|
||||
:param src: The path to Blender composition file to be rendered.
|
||||
:param dst: The path to rendered PNG file.
|
||||
:param cfg: The configuration when rendering Blender composition file. Default for vanilla artifact.
|
||||
"""
|
||||
self.__intern_render_blender(src, dst, cfg)
|
||||
|
||||
def render_blender_then_load(
|
||||
self,
|
||||
src: Path,
|
||||
dst: Optional[Path] = None,
|
||||
cfg: BlenderConfig = _DEFAULT_BLD_CONFIG,
|
||||
) -> Artifact:
|
||||
"""
|
||||
Render given Blender composition to PNG file, then load it directly.
|
||||
|
||||
:param src: The path to Blender composition file to be rendered.
|
||||
:param dst: The path to rendered PNG file.
|
||||
``None`` if you don't need to store it in temporary or output directory.
|
||||
:param cfg: The configuration when rendering Blender composition file. Default for vanilla artifact.
|
||||
:return: The loaded built PNG file.
|
||||
"""
|
||||
dst = self.__intern_render_blender(src, dst, cfg)
|
||||
return artio.load_artifact(dst)
|
||||
|
||||
# endregion
|
||||
|
||||
# region: Advanced Saver
|
||||
|
||||
def __fd_artifact(self, hw: int, kind: FdContext, name: str) -> Path:
|
||||
return self.__context.output_artifact(f"{hw}x{hw}", str(kind), f"{name}.png")
|
||||
|
||||
def save_fd_artifact(self, art: Artifact, kind: FdContext, name: str) -> None:
|
||||
"""
|
||||
Save icon following FreeDesktop icon theme specification.
|
||||
|
||||
:param name: The name of saved artifact. The file extension ".png" is not required.
|
||||
"""
|
||||
logging.info(
|
||||
"Saving FreeDesktop artifact with kind %s and name %s.", kind, name
|
||||
)
|
||||
|
||||
for hw, thumbnail in zip(
|
||||
_FD_THUMBNAIL_HWS, artrender.render_thumbnail(art, _FD_THUMBNAIL_HWS)
|
||||
):
|
||||
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")
|
||||
|
||||
def save_win_artifact(self, art: Artifact, kind: WinCategory, name: str) -> None:
|
||||
"""
|
||||
Save icon for Windows-only
|
||||
|
||||
:param name: The name of saved artifact. The file extension ".ico" is not required.
|
||||
"""
|
||||
logging.info(
|
||||
"Saving Windows-only artifact with kind %s and name %s.", 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:
|
||||
return self.__context.output_artifact(_ART_MAC, str(kind), f"{name}.icns")
|
||||
|
||||
def save_mac_artifact(self, art: Artifact, kind: MacCategory, name: str) -> None:
|
||||
"""
|
||||
Save icon for macOS-only
|
||||
|
||||
:param name: The name of saved artifact. The file extension ".icns" is not required.
|
||||
"""
|
||||
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
|
||||
@@ -1,60 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class MinMaxRect:
|
||||
x1: int
|
||||
y1: int
|
||||
x2: int
|
||||
y2: int
|
||||
|
||||
def to_pos_size_rect(self) -> "PosSizeRect":
|
||||
return PosSizeRect(
|
||||
x=self.x1, y=self.y1, width=self.x2 - self.x1, height=self.y2 - self.y1
|
||||
)
|
||||
|
||||
def to_pillow_tuple(self) -> tuple[int, int, int, int]:
|
||||
return (self.x1, self.y1, self.x2, self.y2)
|
||||
|
||||
@dataclass
|
||||
class PosSizeRect:
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
|
||||
def to_min_max_rect(self) -> MinMaxRect:
|
||||
return MinMaxRect(
|
||||
x1=self.x, y1=self.y, x2=self.x + self.width, y2=self.y + self.height
|
||||
)
|
||||
|
||||
def to_pillow_tuple(self) -> tuple[int, int]:
|
||||
return (self.x, self.y)
|
||||
|
||||
@dataclass
|
||||
class MarginRect:
|
||||
top: int
|
||||
right: int
|
||||
bottom: int
|
||||
left: int
|
||||
|
||||
def to_min_max_rect(self, width: int, height: int) -> MinMaxRect:
|
||||
return MinMaxRect(
|
||||
x1=self.left,
|
||||
y1=self.top,
|
||||
x2=width - self.right,
|
||||
y2=height - self.bottom,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PaddingRect:
|
||||
top: int
|
||||
right: int
|
||||
bottom: int
|
||||
left: int
|
||||
|
||||
def to_min_max_rect(self, x: int, y: int) -> MinMaxRect:
|
||||
return MinMaxRect(
|
||||
x1=x - self.left, y1=y - self.top, x2=x + self.right, y2=y + self.bottom
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
import logging
|
||||
from PIL.Image import Image
|
||||
from PIL.ImageFile import ImageFile
|
||||
|
||||
type Artifact = Image
|
||||
type ArtifactFile = ImageFile
|
||||
|
||||
|
||||
def setup_logging() -> None:
|
||||
logging.basicConfig(format="[%(levelname)s] %(message)s", level=logging.INFO)
|
||||
|
||||
|
||||
VANILLA_ARTIFACT_HW: int = 1024
|
||||
|
||||
|
||||
def check_vanilla_artifact(art: Artifact) -> None:
|
||||
if art.size != (VANILLA_ARTIFACT_HW, VANILLA_ARTIFACT_HW):
|
||||
raise ValueError(
|
||||
f"Icon art must be {VANILLA_ARTIFACT_HW}x{VANILLA_ARTIFACT_HW}, got {art.width}x{art.height} instead"
|
||||
)
|
||||
@@ -1,42 +1,31 @@
|
||||
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
|
||||
from typing import Optional
|
||||
from assemblicon.cli import (
|
||||
SvgRenderKind,
|
||||
StdOptsSetup,
|
||||
create_argparser,
|
||||
parse_standard_opts,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Cli:
|
||||
svg_render: SvgRender
|
||||
class AuroraOpts:
|
||||
selection: Optional[list[str]]
|
||||
"""The list holding all name of jobs for building."""
|
||||
svg_render: SvgRenderKind
|
||||
"""The render kind for SVG file."""
|
||||
|
||||
|
||||
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,
|
||||
def parse() -> AuroraOpts:
|
||||
setup = StdOptsSetup(require_input=False, require_output=False)
|
||||
|
||||
parser = create_argparser(setup)
|
||||
parser.prog = "Aurora Icon Set Builder"
|
||||
parser.description = "The Programmatic Icon Assembly Workflow for Aurora Icon Set."
|
||||
|
||||
ns = parser.parse_args()
|
||||
opts = parse_standard_opts(setup, ns)
|
||||
|
||||
return AuroraOpts(
|
||||
selection=opts.selection, svg_render=opts.svg_render.to_assemblicon_type()
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from ..assemblicon.context import AdvancedContext
|
||||
from .mimetype_icons import build_mimetype_icons
|
||||
from ..types import AuroraContext
|
||||
from . import action_icons, application_icons, mimetype_icons
|
||||
|
||||
|
||||
def build_non_standard_icons(ctx: AdvancedContext) -> None:
|
||||
build_mimetype_icons(ctx)
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
action_icons.register(ctx)
|
||||
application_icons.register(ctx)
|
||||
mimetype_icons.register(ctx)
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
from ..types import AuroraContext, AuroraEnvironment
|
||||
from assemblicon.highlevel.utils import FdContext, VART_HW
|
||||
from assemblicon.highlevel.source import TempArtSource, NewArtSource
|
||||
from assemblicon.highlevel.sink import FdArtSink
|
||||
from assemblicon.geometry import Rectangle
|
||||
from assemblicon.lowlevel.artproc import (
|
||||
art_anchor_to_offset,
|
||||
anchor_to_offset,
|
||||
default_art_resize,
|
||||
align_paste,
|
||||
align_alpha_composite,
|
||||
VerticalAnchor,
|
||||
HorizontalAnchor,
|
||||
)
|
||||
|
||||
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
ctx.register(
|
||||
"nostd/action/image-properties",
|
||||
(
|
||||
TempArtSource("image-jpeg.png"),
|
||||
TempArtSource("dialog-infomation.png"),
|
||||
FdArtSink(FdContext.Actions, "image-properties"),
|
||||
),
|
||||
build_image_properties_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"nostd/action/image-zoom-original",
|
||||
(
|
||||
TempArtSource("component", "triangle-left.png"),
|
||||
TempArtSource("component", "triangle-down.png"),
|
||||
TempArtSource("component", "triangle-right.png"),
|
||||
TempArtSource("component", "triangle-up.png"),
|
||||
TempArtSource("image-jpeg.png"),
|
||||
NewArtSource(),
|
||||
FdArtSink(FdContext.Actions, "image-zoom-original"),
|
||||
),
|
||||
build_image_zoom_original_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"nostd/action/monitor-zoom-fit-best",
|
||||
(
|
||||
TempArtSource("component", "triangle-left.png"),
|
||||
TempArtSource("component", "triangle-down.png"),
|
||||
TempArtSource("component", "triangle-right.png"),
|
||||
TempArtSource("component", "triangle-up.png"),
|
||||
TempArtSource("component", "monitor.png"),
|
||||
NewArtSource(),
|
||||
FdArtSink(FdContext.Actions, "monitor-zoom-fit-best"),
|
||||
),
|
||||
build_monitor_zoom_fit_best_icon,
|
||||
)
|
||||
|
||||
|
||||
def build_image_properties_icon(
|
||||
env: AuroraEnvironment,
|
||||
jpeg_src: TempArtSource,
|
||||
infomation_src: TempArtSource,
|
||||
fd_sink: FdArtSink,
|
||||
) -> None:
|
||||
art = jpeg_src.pull(env)
|
||||
|
||||
info_mark = infomation_src.pull(env)
|
||||
resized_info_mark = default_art_resize(info_mark, 500, 500)
|
||||
|
||||
align_alpha_composite(
|
||||
art,
|
||||
resized_info_mark,
|
||||
art_anchor_to_offset(art, HorizontalAnchor.Right, VerticalAnchor.Bottom),
|
||||
art_anchor_to_offset(
|
||||
resized_info_mark, HorizontalAnchor.Right, VerticalAnchor.Bottom
|
||||
),
|
||||
)
|
||||
|
||||
# save artifact
|
||||
fd_sink.push(env, art)
|
||||
|
||||
|
||||
def build_image_zoom_original_icon(
|
||||
env: AuroraEnvironment,
|
||||
tri_left_src: TempArtSource,
|
||||
tri_down_src: TempArtSource,
|
||||
tri_right_src: TempArtSource,
|
||||
tri_up_src: TempArtSource,
|
||||
inner_src: TempArtSource,
|
||||
new_art: NewArtSource,
|
||||
fd_sink: FdArtSink,
|
||||
) -> None:
|
||||
# load triangle assets
|
||||
TRI_SIZE = (200, 200)
|
||||
tri_left = default_art_resize(tri_left_src.pull(env), *TRI_SIZE)
|
||||
tri_down = default_art_resize(tri_down_src.pull(env), *TRI_SIZE)
|
||||
tri_right = default_art_resize(tri_right_src.pull(env), *TRI_SIZE)
|
||||
tri_up = default_art_resize(tri_up_src.pull(env), *TRI_SIZE)
|
||||
|
||||
# load inner image
|
||||
inner = inner_src.pull(env)
|
||||
resized_inner = default_art_resize(inner, 680, 680)
|
||||
|
||||
# composite this icon
|
||||
icon = new_art.pull()
|
||||
|
||||
align_paste(
|
||||
icon,
|
||||
resized_inner,
|
||||
art_anchor_to_offset(icon, HorizontalAnchor.Center, VerticalAnchor.Center),
|
||||
art_anchor_to_offset(
|
||||
resized_inner, HorizontalAnchor.Center, VerticalAnchor.Center
|
||||
),
|
||||
)
|
||||
|
||||
tri_rect = Rectangle.from_margin_rect(VART_HW, VART_HW, 100, 0, 100, 0)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_left,
|
||||
anchor_to_offset(
|
||||
tri_rect.width,
|
||||
tri_rect.height,
|
||||
HorizontalAnchor.Left,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_left, HorizontalAnchor.Left, VerticalAnchor.Center),
|
||||
)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_right,
|
||||
anchor_to_offset(
|
||||
tri_rect.width,
|
||||
tri_rect.height,
|
||||
HorizontalAnchor.Right,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_right, HorizontalAnchor.Right, VerticalAnchor.Center),
|
||||
)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_up,
|
||||
anchor_to_offset(
|
||||
tri_rect.width, tri_rect.height, HorizontalAnchor.Center, VerticalAnchor.Top
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_up, HorizontalAnchor.Center, VerticalAnchor.Top),
|
||||
)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_down,
|
||||
anchor_to_offset(
|
||||
tri_rect.width,
|
||||
tri_rect.height,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Bottom,
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_down, HorizontalAnchor.Center, VerticalAnchor.Bottom),
|
||||
)
|
||||
|
||||
# save it
|
||||
fd_sink.push(env, icon)
|
||||
|
||||
def build_monitor_zoom_fit_best_icon(
|
||||
env: AuroraEnvironment,
|
||||
tri_left_src: TempArtSource,
|
||||
tri_down_src: TempArtSource,
|
||||
tri_right_src: TempArtSource,
|
||||
tri_up_src: TempArtSource,
|
||||
inner_src: TempArtSource,
|
||||
new_art: NewArtSource,
|
||||
fd_sink: FdArtSink,
|
||||
) -> None:
|
||||
# load triangle assets
|
||||
TRI_SIZE = (200, 200)
|
||||
tri_left = default_art_resize(tri_left_src.pull(env), *TRI_SIZE)
|
||||
tri_down = default_art_resize(tri_down_src.pull(env), *TRI_SIZE)
|
||||
tri_right = default_art_resize(tri_right_src.pull(env), *TRI_SIZE)
|
||||
tri_up = default_art_resize(tri_up_src.pull(env), *TRI_SIZE)
|
||||
|
||||
# load inner image
|
||||
inner = inner_src.pull(env)
|
||||
resized_inner = default_art_resize(inner, 620, 620)
|
||||
|
||||
# composite this icon
|
||||
icon = new_art.pull()
|
||||
|
||||
align_paste(
|
||||
icon,
|
||||
resized_inner,
|
||||
art_anchor_to_offset(icon, HorizontalAnchor.Center, VerticalAnchor.Center),
|
||||
art_anchor_to_offset(
|
||||
resized_inner, HorizontalAnchor.Center, VerticalAnchor.Center
|
||||
),
|
||||
)
|
||||
|
||||
tri_rect = Rectangle.from_margin_rect(VART_HW, VART_HW, 100, 0, 100, 0)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_right,
|
||||
anchor_to_offset(
|
||||
tri_rect.width,
|
||||
tri_rect.height,
|
||||
HorizontalAnchor.Left,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_right, HorizontalAnchor.Left, VerticalAnchor.Center),
|
||||
)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_left,
|
||||
anchor_to_offset(
|
||||
tri_rect.width,
|
||||
tri_rect.height,
|
||||
HorizontalAnchor.Right,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_left, HorizontalAnchor.Right, VerticalAnchor.Center),
|
||||
)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_down,
|
||||
anchor_to_offset(
|
||||
tri_rect.width, tri_rect.height, HorizontalAnchor.Center, VerticalAnchor.Top
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_down, HorizontalAnchor.Center, VerticalAnchor.Top),
|
||||
)
|
||||
align_alpha_composite(
|
||||
icon,
|
||||
tri_up,
|
||||
anchor_to_offset(
|
||||
tri_rect.width,
|
||||
tri_rect.height,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Bottom,
|
||||
)
|
||||
+ tri_rect.pos1,
|
||||
art_anchor_to_offset(tri_up, HorizontalAnchor.Center, VerticalAnchor.Bottom),
|
||||
)
|
||||
|
||||
# save it
|
||||
fd_sink.push(env, icon)
|
||||
@@ -0,0 +1,82 @@
|
||||
from ..types import AuroraContext, AuroraEnvironment
|
||||
from assemblicon.highlevel.utils import FdContext, WinCategory, MacCategory
|
||||
from assemblicon.highlevel.source import (
|
||||
SvgSource,
|
||||
TempArtSource,
|
||||
NewArtSource,
|
||||
BlenderSource,
|
||||
)
|
||||
from assemblicon.highlevel.sink import FdArtSink, WinArtSink, MacArtSink, TempArtSink
|
||||
from assemblicon.lowlevel.artproc import (
|
||||
art_anchor_to_offset,
|
||||
default_art_resize,
|
||||
align_paste,
|
||||
VerticalAnchor,
|
||||
HorizontalAnchor,
|
||||
)
|
||||
|
||||
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
ctx.register(
|
||||
"nostd/application/org.sarasaschipworkshop.picture",
|
||||
(
|
||||
SvgSource("apps", "sarasacw-picture-frame.svg"),
|
||||
TempArtSource("image-jpeg.png"),
|
||||
NewArtSource(),
|
||||
FdArtSink(FdContext.Applications, "org.sarasaschipworkshop.picture"),
|
||||
WinArtSink(WinCategory.Application, "sarasacw-picture"),
|
||||
MacArtSink(MacCategory.Application, "sarasacw-picture"),
|
||||
),
|
||||
build_sarasacw_picture_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"nostd/application/notepad",
|
||||
(
|
||||
BlenderSource("apps", "notepad.blend"),
|
||||
TempArtSink("notepad.png"),
|
||||
WinArtSink(WinCategory.Application, "notepad"),
|
||||
),
|
||||
build_notepad_icon,
|
||||
)
|
||||
|
||||
|
||||
def build_sarasacw_picture_icon(
|
||||
env: AuroraEnvironment,
|
||||
frame_src: SvgSource,
|
||||
inner_src: TempArtSource,
|
||||
new_art: NewArtSource,
|
||||
fd_sink: FdArtSink,
|
||||
win_sink: WinArtSink,
|
||||
mac_sink: MacArtSink,
|
||||
) -> None:
|
||||
app = new_art.pull()
|
||||
frame = frame_src.pull(env)
|
||||
|
||||
inner = inner_src.pull(env)
|
||||
resized_inner = default_art_resize(inner, 990, 990)
|
||||
|
||||
align_paste(
|
||||
app,
|
||||
resized_inner,
|
||||
art_anchor_to_offset(app, HorizontalAnchor.Center, VerticalAnchor.Center),
|
||||
art_anchor_to_offset(
|
||||
resized_inner, HorizontalAnchor.Center, VerticalAnchor.Center
|
||||
),
|
||||
)
|
||||
app.alpha_composite(frame, (0, 0))
|
||||
|
||||
# save artifact
|
||||
fd_sink.push(env, app)
|
||||
win_sink.push(env, app)
|
||||
mac_sink.push(env, app)
|
||||
|
||||
|
||||
def build_notepad_icon(
|
||||
env: AuroraEnvironment,
|
||||
src: BlenderSource,
|
||||
temp_sink: TempArtSink,
|
||||
win_sink: WinArtSink,
|
||||
) -> None:
|
||||
src.pull_to_temp(env, temp_sink)
|
||||
with temp_sink.repull(env) as art:
|
||||
win_sink.push(env, art)
|
||||
@@ -1,71 +1,8 @@
|
||||
import PIL.Image
|
||||
import PIL.ImageEnhance
|
||||
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
|
||||
from ..assemblicon.artproc import (
|
||||
aspect_ratio_scale_and_crop,
|
||||
VerticalAnchor,
|
||||
HorizontalAnchor,
|
||||
)
|
||||
from ..types import AuroraContext, AuroraEnvironment
|
||||
from assemblicon.highlevel.utils import FdContext, WinCategory, MacCategory
|
||||
from assemblicon.highlevel.source import SvgSource, TempArtSource
|
||||
from assemblicon.highlevel.sink import TempArtSink, FdArtSink, WinArtSink, MacArtSink
|
||||
|
||||
|
||||
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: AdvancedContext) -> None:
|
||||
# build image base
|
||||
image_base = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "image-base.svg"),
|
||||
)
|
||||
# load image base
|
||||
with image_base:
|
||||
_build_jpg_icon(ctx, image_base)
|
||||
|
||||
|
||||
def _build_jpg_icon(ctx: AdvancedContext, base: Artifact) -> None:
|
||||
jpg_image = base.copy()
|
||||
|
||||
jpg_image_inner = load_input_artifact(
|
||||
ctx.input_artifact("ext", "bitmap", "Niinsaare_järv.jpg")
|
||||
)
|
||||
with jpg_image_inner:
|
||||
# crop the area which is interested by ourselves
|
||||
interest_area = PosSizeRect(2700, 0, 5016, 3888).to_min_max_rect()
|
||||
crop_jpg_image_inner = jpg_image_inner.crop(interest_area.to_pillow_tuple())
|
||||
# do a flip
|
||||
flip_jpg_image_inner = crop_jpg_image_inner.transpose(
|
||||
PIL.Image.Transpose.FLIP_LEFT_RIGHT
|
||||
)
|
||||
# enhance its saturation
|
||||
enhancer = PIL.ImageEnhance.Color(flip_jpg_image_inner)
|
||||
saturated_jpg_image_inner = enhancer.enhance(1.4)
|
||||
|
||||
# fit to inner rect
|
||||
bestfit_jpg_image_inner = aspect_ratio_scale_and_crop(
|
||||
saturated_jpg_image_inner,
|
||||
IMAGE_INNER_RECT_POSSIZE.width,
|
||||
IMAGE_INNER_RECT_POSSIZE.height,
|
||||
PIL.Image.Resampling.NEAREST,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
# paste into inner rect
|
||||
jpg_image.paste(
|
||||
bestfit_jpg_image_inner, IMAGE_INNER_RECT_POSSIZE.to_pillow_tuple()
|
||||
)
|
||||
|
||||
# build artifacts
|
||||
# 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")
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
pass
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from ..assemblicon.context import AdvancedContext
|
||||
from .action_icons import build_action_icons
|
||||
from ..types import AuroraContext
|
||||
from . import components, action_icons, status_icons, mimetype_icons
|
||||
|
||||
|
||||
def build_standard_icons(ctx: AdvancedContext) -> None:
|
||||
build_action_icons(ctx)
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
components.register(ctx)
|
||||
action_icons.register(ctx)
|
||||
mimetype_icons.register(ctx)
|
||||
status_icons.register(ctx)
|
||||
|
||||
@@ -1,34 +1,176 @@
|
||||
import PIL.Image
|
||||
from ..assemblicon.context import AdvancedContext, FdContext
|
||||
from ..types import AuroraContext, AuroraEnvironment
|
||||
from assemblicon.geometry import Rectangle, Point
|
||||
from assemblicon.lowlevel.artproc import default_art_resize, align_alpha_composite
|
||||
from assemblicon.highlevel.utils import FdContext
|
||||
from assemblicon.highlevel.source import SvgSource, TempArtSource
|
||||
from assemblicon.highlevel.sink import FdArtSink
|
||||
|
||||
|
||||
def build_action_icons(ctx: AdvancedContext) -> None:
|
||||
_build_go_icons(ctx)
|
||||
|
||||
|
||||
def _build_go_icons(ctx: AdvancedContext) -> None:
|
||||
# build go-* base
|
||||
go_base = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "go-base.svg")
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
ctx.register(
|
||||
"std/action/go-[previous|down|next|up]",
|
||||
(
|
||||
SvgSource("go-base.svg"),
|
||||
SvgSource("go-inner-shining.svg"),
|
||||
SvgSource("go-inner.svg"),
|
||||
FdArtSink(FdContext.Actions, "go-previous"),
|
||||
FdArtSink(FdContext.Actions, "go-down"),
|
||||
FdArtSink(FdContext.Actions, "go-next"),
|
||||
FdArtSink(FdContext.Actions, "go-up"),
|
||||
),
|
||||
build_go_icons,
|
||||
)
|
||||
# build go-* shining
|
||||
go_inner_shining = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "go-inner-shining.svg"),
|
||||
|
||||
ctx.register(
|
||||
"std/action/object-flip-horizontal",
|
||||
(
|
||||
SvgSource("object-flip-horizontal.svg"),
|
||||
FdArtSink(FdContext.Actions, "object-flip-horizontal"),
|
||||
),
|
||||
build_object_flip_horizontal_icon,
|
||||
)
|
||||
# build go-* inner
|
||||
go_inner = ctx.render_svg_then_load(
|
||||
ctx.input_artifact("component", "go-inner.svg"),
|
||||
ctx.register(
|
||||
"std/action/object-flip-vertical",
|
||||
(
|
||||
SvgSource("object-flip-vertical.svg"),
|
||||
FdArtSink(FdContext.Actions, "object-flip-vertical"),
|
||||
),
|
||||
build_object_flip_vertical_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/action/object-rotate-left",
|
||||
(
|
||||
SvgSource("object-rotate-left.svg"),
|
||||
FdArtSink(FdContext.Actions, "object-rotate-left"),
|
||||
),
|
||||
build_object_rotate_left_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/action/object-rotate-right",
|
||||
(
|
||||
SvgSource("object-rotate-right.svg"),
|
||||
FdArtSink(FdContext.Actions, "object-rotate-right"),
|
||||
),
|
||||
build_object_rotate_right_icon,
|
||||
)
|
||||
|
||||
ctx.register(
|
||||
"std/action/zoom-[original|fit-best]",
|
||||
(
|
||||
TempArtSource("component", "triangle-left.png"),
|
||||
TempArtSource("component", "triangle-down.png"),
|
||||
TempArtSource("component", "triangle-right.png"),
|
||||
TempArtSource("component", "triangle-up.png"),
|
||||
FdArtSink(FdContext.Actions, "zoom-original"),
|
||||
FdArtSink(FdContext.Actions, "zoom-fit-best"),
|
||||
),
|
||||
build_zoom_origin_and_fit_best_icons,
|
||||
)
|
||||
ctx.register(
|
||||
"std/action/zoom-[in|out]",
|
||||
(
|
||||
TempArtSource("component", "magnifying-glass.png"),
|
||||
TempArtSource("component", "plus.png"),
|
||||
TempArtSource("component", "minus.png"),
|
||||
FdArtSink(FdContext.Actions, "zoom-in"),
|
||||
FdArtSink(FdContext.Actions, "zoom-out"),
|
||||
),
|
||||
build_zoom_in_out_icons,
|
||||
)
|
||||
|
||||
|
||||
def build_go_icons(
|
||||
env: AuroraEnvironment,
|
||||
base_src: SvgSource,
|
||||
shining_src: SvgSource,
|
||||
inner_src: SvgSource,
|
||||
sink_previous: FdArtSink,
|
||||
sink_down: FdArtSink,
|
||||
sink_next: FdArtSink,
|
||||
sink_up: FdArtSink,
|
||||
) -> None:
|
||||
# build go-* base, shining and inner
|
||||
go_base = base_src.pull(env)
|
||||
go_inner_shining = shining_src.pull(env)
|
||||
go_inner = inner_src.pull(env)
|
||||
|
||||
with go_base, go_inner_shining, go_inner:
|
||||
go_mask = go_inner
|
||||
for part in ("previous", "down", "next", "up"):
|
||||
for sink in (sink_previous, sink_down, sink_next, sink_up):
|
||||
go = go_base.copy()
|
||||
# render shining with inner mask
|
||||
go.paste(go_inner_shining, (0, 0), go_mask)
|
||||
|
||||
|
||||
# save as FD action
|
||||
ctx.save_fd_artifact(go, FdContext.Actions, f'go-{part}')
|
||||
sink.push(env, go)
|
||||
|
||||
# rotate it for next calling
|
||||
go_mask = go_mask.transpose(PIL.Image.Transpose.ROTATE_90)
|
||||
|
||||
|
||||
def build_object_flip_horizontal_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, sink: FdArtSink
|
||||
) -> None:
|
||||
with src.pull(env) as art:
|
||||
sink.push(env, art)
|
||||
|
||||
|
||||
def build_object_flip_vertical_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, sink: FdArtSink
|
||||
) -> None:
|
||||
with src.pull(env) as art:
|
||||
sink.push(env, art)
|
||||
|
||||
|
||||
def build_object_rotate_left_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, sink: FdArtSink
|
||||
) -> None:
|
||||
with src.pull(env) as art:
|
||||
sink.push(env, art)
|
||||
|
||||
|
||||
def build_object_rotate_right_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, sink: FdArtSink
|
||||
) -> None:
|
||||
with src.pull(env) as art:
|
||||
sink.push(env, art)
|
||||
|
||||
|
||||
def build_zoom_origin_and_fit_best_icons(
|
||||
env: AuroraEnvironment,
|
||||
tri_left_src: TempArtSource,
|
||||
tri_down_src: TempArtSource,
|
||||
tri_right_src: TempArtSource,
|
||||
tri_up_src: TempArtSource,
|
||||
zoom_original_sink: FdArtSink,
|
||||
zoom_fit_best_sink: FdArtSink,
|
||||
) -> None:
|
||||
# TODO: finish this in future
|
||||
pass
|
||||
|
||||
|
||||
def build_zoom_in_out_icons(
|
||||
env: AuroraEnvironment,
|
||||
magnifying_glass_source: TempArtSource,
|
||||
plus_source: TempArtSource,
|
||||
minus_source: TempArtSource,
|
||||
zoom_in_sink: FdArtSink,
|
||||
zoom_out_sink: FdArtSink,
|
||||
) -> None:
|
||||
magnifying_glass = magnifying_glass_source.pull(env)
|
||||
magnifying_glass_rect = Rectangle.from_padding_rect(
|
||||
Point(665, 355), 200, 200, 200, 200
|
||||
)
|
||||
|
||||
inner_size = (magnifying_glass_rect.width, magnifying_glass_rect.height)
|
||||
plus = default_art_resize(plus_source.pull(env), *inner_size)
|
||||
minus = default_art_resize(minus_source.pull(env), *inner_size)
|
||||
|
||||
zoom_in = magnifying_glass.copy()
|
||||
align_alpha_composite(zoom_in, plus, magnifying_glass_rect.pos1, Point(0, 0))
|
||||
zoom_in_sink.push(env, zoom_in)
|
||||
|
||||
zoom_out = magnifying_glass.copy()
|
||||
align_alpha_composite(zoom_out, minus, magnifying_glass_rect.pos1, Point(0, 0))
|
||||
zoom_out_sink.push(env, zoom_out)
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import PIL.Image
|
||||
from ..types import AuroraContext, AuroraEnvironment
|
||||
from assemblicon.highlevel.source import (
|
||||
SvgSource,
|
||||
TempArtSource,
|
||||
NewArtSource,
|
||||
BlenderSource,
|
||||
)
|
||||
from assemblicon.highlevel.sink import TempArtSink
|
||||
|
||||
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
ctx.register(
|
||||
"component/generic-background",
|
||||
(
|
||||
SvgSource("component", "generic-background.svg"),
|
||||
TempArtSink("component", "generic-background.png"),
|
||||
),
|
||||
build_generic_background,
|
||||
)
|
||||
ctx.register(
|
||||
"component/triangles",
|
||||
(
|
||||
SvgSource("component", "triangle.svg"),
|
||||
TempArtSource("component", "generic-background.png"),
|
||||
NewArtSource(),
|
||||
TempArtSink("component", "triangle-left.png"),
|
||||
TempArtSink("component", "triangle-down.png"),
|
||||
TempArtSink("component", "triangle-right.png"),
|
||||
TempArtSink("component", "triangle-up.png"),
|
||||
),
|
||||
build_triangle_icons,
|
||||
)
|
||||
ctx.register(
|
||||
"component/plus_minus",
|
||||
(
|
||||
TempArtSource("component", "generic-background.png"),
|
||||
SvgSource("component", "plus.svg"),
|
||||
SvgSource("component", "minus.svg"),
|
||||
NewArtSource(),
|
||||
TempArtSink("component", "plus.png"),
|
||||
TempArtSink("component", "minus.png"),
|
||||
),
|
||||
build_plus_minus_icons,
|
||||
)
|
||||
ctx.register(
|
||||
"component/magnifying-glass",
|
||||
(
|
||||
BlenderSource("component", "magnifying-glass.blend"),
|
||||
TempArtSink("component", "magnifying-glass.png"),
|
||||
),
|
||||
build_magnifying_glass_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"component/monitor",
|
||||
(
|
||||
SvgSource("component", "monitor.svg"),
|
||||
TempArtSink("component", "monitor.png"),
|
||||
),
|
||||
build_generic_background,
|
||||
)
|
||||
|
||||
|
||||
def build_generic_background(
|
||||
env: AuroraEnvironment, src: SvgSource, sink: TempArtSink
|
||||
) -> None:
|
||||
src.pull_to_temp(env, sink)
|
||||
|
||||
|
||||
def build_triangle_icons(
|
||||
env: AuroraEnvironment,
|
||||
tri_src: SvgSource,
|
||||
bg_src: TempArtSource,
|
||||
new_art: NewArtSource,
|
||||
sink_left: TempArtSink,
|
||||
sink_down: TempArtSink,
|
||||
sink_right: TempArtSink,
|
||||
sink_up: TempArtSink,
|
||||
) -> None:
|
||||
# load triangle and background assets
|
||||
tri = tri_src.pull(env)
|
||||
bg = bg_src.pull(env)
|
||||
|
||||
# create 4 triangle icons for following building
|
||||
tri_left = new_art.pull()
|
||||
tri_left.paste(bg, (0, 0), tri)
|
||||
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
|
||||
|
||||
tri_down = new_art.pull()
|
||||
tri_down.paste(bg, (0, 0), tri)
|
||||
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
|
||||
|
||||
tri_right = new_art.pull()
|
||||
tri_right.paste(bg, (0, 0), tri)
|
||||
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
|
||||
|
||||
tri_up = new_art.pull()
|
||||
tri_up.paste(bg, (0, 0), tri)
|
||||
|
||||
# save them for reuse
|
||||
sink_left.push(env, tri_left)
|
||||
sink_down.push(env, tri_down)
|
||||
sink_right.push(env, tri_right)
|
||||
sink_up.push(env, tri_up)
|
||||
|
||||
|
||||
def build_plus_minus_icons(
|
||||
env: AuroraEnvironment,
|
||||
bg_src: TempArtSource,
|
||||
plus_src: SvgSource,
|
||||
minus_src: SvgSource,
|
||||
new_art: NewArtSource,
|
||||
plus_sink: TempArtSink,
|
||||
minus_sink: TempArtSink,
|
||||
) -> None:
|
||||
bg = bg_src.pull(env)
|
||||
|
||||
plus = plus_src.pull(env)
|
||||
art = new_art.pull()
|
||||
art.paste(bg, (0, 0), plus)
|
||||
plus_sink.push(env, art)
|
||||
|
||||
minus = minus_src.pull(env)
|
||||
art = new_art.pull()
|
||||
art.paste(bg, (0, 0), minus)
|
||||
minus_sink.push(env, art)
|
||||
|
||||
|
||||
def build_magnifying_glass_icon(
|
||||
env: AuroraEnvironment, src: BlenderSource, sink: TempArtSink
|
||||
) -> None:
|
||||
src.pull_to_temp(env, sink)
|
||||
|
||||
|
||||
def build_monitor_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, sink: TempArtSink
|
||||
) -> None:
|
||||
src.pull_to_temp(env, sink)
|
||||
@@ -0,0 +1,270 @@
|
||||
import PIL.Image
|
||||
import PIL.ImageEnhance
|
||||
from ..types import AuroraContext, AuroraEnvironment
|
||||
from assemblicon.highlevel.utils import FdContext, WinCategory, MacCategory
|
||||
from assemblicon.highlevel.source import (
|
||||
SvgSource,
|
||||
BitmapSource,
|
||||
TempArtSource,
|
||||
FdArtSource,
|
||||
)
|
||||
from assemblicon.highlevel.sink import TempArtSink, FdArtSink, WinArtSink, MacArtSink
|
||||
from assemblicon.geometry import Rectangle, Point
|
||||
from assemblicon.lowlevel.artio import new_artifact
|
||||
from assemblicon.lowlevel.artproc import (
|
||||
aspect_ratio_scale_and_crop,
|
||||
VerticalAnchor,
|
||||
HorizontalAnchor,
|
||||
)
|
||||
|
||||
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
ctx.register(
|
||||
"component/image-base",
|
||||
(
|
||||
SvgSource("component", "image-base.svg"),
|
||||
TempArtSink("component", "image-base.png"),
|
||||
),
|
||||
build_image_base_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/mimetype/image-x-generic",
|
||||
(
|
||||
FdArtSource(FdContext.MimeTypes, "image-jpeg"),
|
||||
FdArtSink(FdContext.MimeTypes, "image-x-generic"),
|
||||
),
|
||||
build_image_x_generic,
|
||||
)
|
||||
ctx.register(
|
||||
"std/mimetype/image-jpeg",
|
||||
(
|
||||
TempArtSource("component", "image-base.png"),
|
||||
BitmapSource("bitmap", "Niinsaare_järv.jpg"),
|
||||
TempArtSink("image-jpeg.png"),
|
||||
FdArtSink(FdContext.MimeTypes, "image-jpeg"),
|
||||
WinArtSink(WinCategory.Extension, "jpg"),
|
||||
MacArtSink(MacCategory.Extension, "jpg"),
|
||||
),
|
||||
build_image_jpeg_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/mimetype/image-png",
|
||||
(
|
||||
TempArtSource("component", "image-base.png"),
|
||||
BitmapSource("bitmap", "Tulipa_suaveolens_floriade_to_Canberra.jpg"),
|
||||
BitmapSource("bitmap", "Tulipa_suaveolens_floriade_to_Canberra-mask.png"),
|
||||
SvgSource("image-png-checkerboard.svg"),
|
||||
FdArtSink(FdContext.MimeTypes, "image-png"),
|
||||
WinArtSink(WinCategory.Extension, "png"),
|
||||
MacArtSink(MacCategory.Extension, "png"),
|
||||
),
|
||||
build_image_png_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/mimetype/image-bmp",
|
||||
(
|
||||
TempArtSource("component", "image-base.png"),
|
||||
BitmapSource("bitmap", "Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg"),
|
||||
FdArtSink(FdContext.MimeTypes, "image-bmp"),
|
||||
WinArtSink(WinCategory.Extension, "bmp"),
|
||||
MacArtSink(MacCategory.Extension, "bmp"),
|
||||
),
|
||||
build_image_bmp_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/mimetype/image-gif",
|
||||
(
|
||||
TempArtSource("component", "image-base.png"),
|
||||
BitmapSource("bitmap", "Hot-air_balloon_in_Tambov_-_02.jpg"),
|
||||
FdArtSink(FdContext.MimeTypes, "image-gif"),
|
||||
WinArtSink(WinCategory.Extension, "gif"),
|
||||
MacArtSink(MacCategory.Extension, "gif"),
|
||||
),
|
||||
build_image_gif_icon,
|
||||
)
|
||||
|
||||
|
||||
def build_image_base_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, sink: TempArtSink
|
||||
) -> None:
|
||||
src.pull_to_temp(env, sink)
|
||||
|
||||
|
||||
def build_image_x_generic(
|
||||
env: AuroraEnvironment, src: FdArtSource, sink: FdArtSink
|
||||
) -> None:
|
||||
# use image/jpeg as the default image icon
|
||||
src.link_to(env, sink)
|
||||
|
||||
|
||||
IMAGE_INNER_RECT = Rectangle(Point(20 * 4, 52 * 4), Point(236 * 4, 204 * 4))
|
||||
"""The valid region of image-base for putting inner image."""
|
||||
|
||||
|
||||
def build_image_jpeg_icon(
|
||||
env: AuroraEnvironment,
|
||||
base_src: TempArtSource,
|
||||
bitmap_src: BitmapSource,
|
||||
temp_sink: TempArtSink,
|
||||
fd_sink: FdArtSink,
|
||||
win_sink: WinArtSink,
|
||||
mac_sink: MacArtSink,
|
||||
) -> None:
|
||||
jpg_image = base_src.pull(env)
|
||||
|
||||
jpg_image_inner = bitmap_src.pull(env)
|
||||
with jpg_image_inner:
|
||||
# crop the area which is interested by ourselves
|
||||
interest_area = Rectangle.from_pos_size_rect(Point(2700, 0), 5016, 3888)
|
||||
crop_jpg_image_inner = jpg_image_inner.crop(interest_area.to_tuple())
|
||||
# do a flip
|
||||
flip_jpg_image_inner = crop_jpg_image_inner.transpose(
|
||||
PIL.Image.Transpose.FLIP_LEFT_RIGHT
|
||||
)
|
||||
# enhance its saturation
|
||||
enhancer = PIL.ImageEnhance.Color(flip_jpg_image_inner)
|
||||
saturated_jpg_image_inner = enhancer.enhance(1.4)
|
||||
|
||||
# fit to inner rect
|
||||
bestfit_jpg_image_inner = aspect_ratio_scale_and_crop(
|
||||
saturated_jpg_image_inner,
|
||||
IMAGE_INNER_RECT.width,
|
||||
IMAGE_INNER_RECT.height,
|
||||
PIL.Image.Resampling.NEAREST,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
# paste into inner rect
|
||||
jpg_image.paste(bestfit_jpg_image_inner, IMAGE_INNER_RECT.to_tuple())
|
||||
|
||||
# build artifacts
|
||||
# save as temporary for future use
|
||||
temp_sink.push(env, jpg_image)
|
||||
# save for FD
|
||||
fd_sink.push(env, jpg_image)
|
||||
# save for windows and mac
|
||||
win_sink.push(env, jpg_image)
|
||||
mac_sink.push(env, jpg_image)
|
||||
|
||||
|
||||
def build_image_png_icon(
|
||||
env: AuroraEnvironment,
|
||||
base_src: TempArtSource,
|
||||
bitmap_src: BitmapSource,
|
||||
bitmap_mask_src: BitmapSource,
|
||||
checkerboard_src: SvgSource,
|
||||
fd_sink: FdArtSink,
|
||||
win_sink: WinArtSink,
|
||||
mac_sink: MacArtSink,
|
||||
) -> None:
|
||||
png_image = base_src.pull(env)
|
||||
|
||||
bitmap = bitmap_src.pull(env)
|
||||
bitmap_mask = bitmap_mask_src.pull(env)
|
||||
checkerboard = checkerboard_src.pull(env)
|
||||
|
||||
with bitmap, bitmap_mask, checkerboard:
|
||||
# mask bitmap first
|
||||
# force mask as grayscale format to apply black-white mask instead of alpha channel mask
|
||||
bitmap_masked = new_artifact(bitmap.size)
|
||||
bitmap_masked.paste(bitmap, (0, 0), bitmap_mask.convert("L"))
|
||||
|
||||
# we use the whole image as the inner,
|
||||
# so we directly fit it to inner.
|
||||
bestfit_bitmap = aspect_ratio_scale_and_crop(
|
||||
bitmap_masked,
|
||||
IMAGE_INNER_RECT.width,
|
||||
IMAGE_INNER_RECT.height,
|
||||
PIL.Image.Resampling.NEAREST,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Top,
|
||||
)
|
||||
# TODO: When bestfit this checkerboard, the border of this checkerboard aer lost.
|
||||
# We may need resolve this in future but currently it is so subtle to notice.
|
||||
bestfit_checkerboard = aspect_ratio_scale_and_crop(
|
||||
checkerboard,
|
||||
IMAGE_INNER_RECT.width,
|
||||
IMAGE_INNER_RECT.height,
|
||||
PIL.Image.Resampling.NEAREST,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
|
||||
# composite them together
|
||||
png_image.alpha_composite(
|
||||
bestfit_checkerboard, IMAGE_INNER_RECT.pos1.to_tuple()
|
||||
)
|
||||
png_image.alpha_composite(bestfit_bitmap, IMAGE_INNER_RECT.pos1.to_tuple())
|
||||
|
||||
# build artifacts
|
||||
# save for FD
|
||||
fd_sink.push(env, png_image)
|
||||
# save for windows and mac
|
||||
win_sink.push(env, png_image)
|
||||
mac_sink.push(env, png_image)
|
||||
|
||||
|
||||
def build_image_bmp_icon(
|
||||
env: AuroraEnvironment,
|
||||
base_src: TempArtSource,
|
||||
bitmap_src: BitmapSource,
|
||||
fd_sink: FdArtSink,
|
||||
win_sink: WinArtSink,
|
||||
mac_sink: MacArtSink,
|
||||
) -> None:
|
||||
bmp_image = base_src.pull(env)
|
||||
|
||||
bmp_image_inner = bitmap_src.pull(env)
|
||||
with bmp_image_inner:
|
||||
# we use the whole image as the inner,
|
||||
# so we directly fit it to inner.
|
||||
bestfit_inner = aspect_ratio_scale_and_crop(
|
||||
bmp_image_inner,
|
||||
IMAGE_INNER_RECT.width,
|
||||
IMAGE_INNER_RECT.height,
|
||||
PIL.Image.Resampling.NEAREST,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
# paste into inner rect
|
||||
bmp_image.paste(bestfit_inner, IMAGE_INNER_RECT.to_tuple())
|
||||
|
||||
# build artifacts
|
||||
# save for FD
|
||||
fd_sink.push(env, bmp_image)
|
||||
# save for windows and mac
|
||||
win_sink.push(env, bmp_image)
|
||||
mac_sink.push(env, bmp_image)
|
||||
|
||||
|
||||
def build_image_gif_icon(
|
||||
env: AuroraEnvironment,
|
||||
base_src: TempArtSource,
|
||||
bitmap_src: BitmapSource,
|
||||
fd_sink: FdArtSink,
|
||||
win_sink: WinArtSink,
|
||||
mac_sink: MacArtSink,
|
||||
) -> None:
|
||||
gif_image = base_src.pull(env)
|
||||
|
||||
gif_image_inner = bitmap_src.pull(env)
|
||||
with gif_image_inner:
|
||||
# we use the whole image as the inner,
|
||||
# so we directly fit it to inner.
|
||||
bestfit_inner = aspect_ratio_scale_and_crop(
|
||||
gif_image_inner,
|
||||
IMAGE_INNER_RECT.width,
|
||||
IMAGE_INNER_RECT.height,
|
||||
PIL.Image.Resampling.NEAREST,
|
||||
HorizontalAnchor.Center,
|
||||
VerticalAnchor.Center,
|
||||
)
|
||||
# paste into inner rect
|
||||
gif_image.paste(bestfit_inner, IMAGE_INNER_RECT.to_tuple())
|
||||
|
||||
# build artifacts
|
||||
# save for FD
|
||||
fd_sink.push(env, gif_image)
|
||||
# save for windows and mac
|
||||
win_sink.push(env, gif_image)
|
||||
mac_sink.push(env, gif_image)
|
||||
@@ -0,0 +1,79 @@
|
||||
from ..types import AuroraContext, AuroraEnvironment
|
||||
from assemblicon.highlevel.utils import FdContext
|
||||
from assemblicon.highlevel.source import SvgSource
|
||||
from assemblicon.highlevel.sink import TempArtSink, FdArtSink
|
||||
|
||||
|
||||
def register(ctx: AuroraContext) -> None:
|
||||
ctx.register(
|
||||
"std/status/dialog-infomation",
|
||||
(
|
||||
SvgSource("dialog-infomation.svg"),
|
||||
TempArtSink("dialog-infomation.png"),
|
||||
FdArtSink(FdContext.Status, "dialog-infomation"),
|
||||
),
|
||||
build_dialog_infomation_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/status/dialog-warning",
|
||||
(
|
||||
SvgSource("dialog-warning.svg"),
|
||||
TempArtSink("dialog-warning.png"),
|
||||
FdArtSink(FdContext.Status, "dialog-warning"),
|
||||
),
|
||||
build_dialog_warning_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/status/dialog-error",
|
||||
(
|
||||
SvgSource("dialog-error.svg"),
|
||||
TempArtSink("dialog-error.png"),
|
||||
FdArtSink(FdContext.Status, "dialog-error"),
|
||||
),
|
||||
build_dialog_error_icon,
|
||||
)
|
||||
ctx.register(
|
||||
"std/status/dialog-question",
|
||||
(
|
||||
SvgSource("dialog-question.svg"),
|
||||
TempArtSink("dialog-question.png"),
|
||||
FdArtSink(FdContext.Status, "dialog-question"),
|
||||
),
|
||||
build_dialog_question_icon,
|
||||
)
|
||||
|
||||
|
||||
def build_dialog_infomation_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, temp_sink: TempArtSink, fd_sink: FdArtSink
|
||||
) -> None:
|
||||
# save dialog icon with FreeDesktop icon and temp icon for reuse.
|
||||
src.pull_to_temp(env, temp_sink)
|
||||
with temp_sink.repull(env) as art:
|
||||
fd_sink.push(env, art)
|
||||
|
||||
|
||||
def build_dialog_warning_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, temp_sink: TempArtSink, fd_sink: FdArtSink
|
||||
) -> None:
|
||||
# save dialog icon with FreeDesktop icon and temp icon for reuse.
|
||||
src.pull_to_temp(env, temp_sink)
|
||||
with temp_sink.repull(env) as art:
|
||||
fd_sink.push(env, art)
|
||||
|
||||
|
||||
def build_dialog_error_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, temp_sink: TempArtSink, fd_sink: FdArtSink
|
||||
) -> None:
|
||||
# TODO: update this icon from rectangle to circle
|
||||
|
||||
# save dialog icon with FreeDesktop icon and temp icon for reuse.
|
||||
src.pull_to_temp(env, temp_sink)
|
||||
with temp_sink.repull(env) as art:
|
||||
fd_sink.push(env, art)
|
||||
|
||||
|
||||
def build_dialog_question_icon(
|
||||
env: AuroraEnvironment, src: SvgSource, temp_sink: TempArtSink, fd_sink: FdArtSink
|
||||
) -> None:
|
||||
# TODO: add dialog-question generation
|
||||
pass
|
||||
@@ -0,0 +1,14 @@
|
||||
from dataclasses import dataclass
|
||||
from assemblicon.highlevel.environment import Environment, Prologue
|
||||
from assemblicon.highlevel.context import Context
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AuroraPrologue(Prologue):
|
||||
"""Aurora icon set builder specific prologue"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
type AuroraEnvironment = Environment[AuroraPrologue]
|
||||
type AuroraContext = Context[AuroraPrologue]
|
||||
Generated
+10
-2
@@ -2,16 +2,24 @@ version = 1
|
||||
revision = 2
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "assemblicon"
|
||||
version = "0.1.0"
|
||||
source = { git = "https://github.com/SarasasChipWorkshop/assemblicon#0073298d45d6c44fc164456ebdec5f0d3ada5dff" }
|
||||
dependencies = [
|
||||
{ name = "pillow" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aurora-iconset-builder"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "pillow" },
|
||||
{ name = "assemblicon" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "pillow", specifier = ">=12.3.0" }]
|
||||
requires-dist = [{ name = "assemblicon", git = "https://github.com/SarasasChipWorkshop/assemblicon" }]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
|
||||
Reference in New Issue
Block a user