feat: finish image-zoom-original

This commit is contained in:
2026-09-03 14:59:06 +08:00
parent da52ab5028
commit d13f18cc90
8 changed files with 92 additions and 64 deletions
@@ -91,7 +91,7 @@ class Rectangle:
@staticmethod @staticmethod
def from_padding_rect( def from_padding_rect(
x: int, y: int, top: int, right: int, bottom: int, left: int pos: Point, top: int, right: int, bottom: int, left: int
) -> "Rectangle": ) -> "Rectangle":
""" """
TODO TODO
@@ -103,7 +103,7 @@ class Rectangle:
:param bottom: The distance from reference point to this rectangle's bottom border. :param bottom: The distance from reference point to this rectangle's bottom border.
:param left: The distance from reference point to this rectangle's left border. :param left: The distance from reference point to this rectangle's left border.
""" """
return Rectangle(Point(x - left, y - top), Point(x + right, y + bottom)) return Rectangle(Point(pos.x - left, pos.y - top), Point(pos.x + right, pos.y + bottom))
@property @property
def width(self) -> int: def width(self) -> int:
@@ -73,7 +73,7 @@ _DEFAULT_BLD_CONFIG = artrdr.BlenderConfig(VART_HW, VART_HW)
# TODO: For easy testing, we only build 32x32 and 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, ...] = (32, 48) _FD_THUMBNAIL_HWS: tuple[int, ...] = (32, 48, 256)
# _FD_THUMBNAIL_HWS: tuple[int, ...] = (16, 32, 48, 64, 128, 256) # _FD_THUMBNAIL_HWS: tuple[int, ...] = (16, 32, 48, 64, 128, 256)
@@ -5,7 +5,7 @@ class LoggerFactory:
def __init__(self) -> None: def __init__(self) -> None:
# setup log format and level # setup log format and level
logging.basicConfig( logging.basicConfig(
format="[%(levelname)s][%(name)s] %(message)s", level=logging.INFO format="[%(levelname)s] [%(name)s] %(message)s", level=logging.INFO
) )
def get_app_logger(self) -> logging.Logger: def get_app_logger(self) -> logging.Logger:
@@ -17,29 +17,28 @@ class VerticalAnchor(enum.IntEnum):
def anchor_to_offset( def anchor_to_offset(
oversize: Point, oversize_width: int,
oversize_height: int,
horizontal_anchor: HorizontalAnchor, horizontal_anchor: HorizontalAnchor,
vertical_anchor: VerticalAnchor, vertical_anchor: VerticalAnchor,
) -> Point: ) -> Point:
half_oversize = oversize // 2
x: int x: int
match horizontal_anchor: match horizontal_anchor:
case HorizontalAnchor.Left: case HorizontalAnchor.Left:
x = 0 x = 0
case HorizontalAnchor.Center: case HorizontalAnchor.Center:
x = half_oversize.x x = oversize_width // 2
case HorizontalAnchor.Right: case HorizontalAnchor.Right:
x = oversize.x x = oversize_width
y: int y: int
match vertical_anchor: match vertical_anchor:
case VerticalAnchor.Top: case VerticalAnchor.Top:
y = 0 y = 0
case VerticalAnchor.Center: case VerticalAnchor.Center:
y = half_oversize.y y = oversize_height // 2
case VerticalAnchor.Bottom: case VerticalAnchor.Bottom:
y = oversize.y y = oversize_height
return Point(x, y) return Point(x, y)
@@ -65,7 +64,8 @@ def aspect_ratio_scale_and_crop(
scaled = art.resize((scaled_width, scaled_height), scale_resample) scaled = art.resize((scaled_width, scaled_height), scale_resample)
crop = anchor_to_offset( crop = anchor_to_offset(
Point(scaled_width - target_width, scaled_height - target_height), scaled_width - target_width,
scaled_height - target_height,
crop_horizontal_anchor, crop_horizontal_anchor,
crop_vertical_anchor, crop_vertical_anchor,
) )
@@ -88,9 +88,7 @@ def art_anchor_to_offset(
anchors this is the corresponding edge; for Right/Bottom anchors anchors this is the corresponding edge; for Right/Bottom anchors
this is just outside the artifact (the exact corner coordinate). this is just outside the artifact (the exact corner coordinate).
""" """
return anchor_to_offset( return anchor_to_offset(*art.size, horizontal_anchor, vertical_anchor)
Point.from_tuple(art.size), horizontal_anchor, vertical_anchor
)
def align_paste( def align_paste(
@@ -1,8 +1,11 @@
import PIL.Image import PIL.Image
from ..types import AuroraContext, AuroraEnvironment from ..types import AuroraContext, AuroraEnvironment
from ..assemblicon.highlevel.environment import FdContext from ..assemblicon.highlevel.environment import FdContext
from ..assemblicon.highlevel.utils import VART_HW
from ..assemblicon.geometry import Rectangle, Point
from ..assemblicon.lowlevel.artproc import ( from ..assemblicon.lowlevel.artproc import (
art_anchor_to_offset, art_anchor_to_offset,
anchor_to_offset,
align_paste, align_paste,
align_alpha_composite, align_alpha_composite,
VerticalAnchor, VerticalAnchor,
@@ -14,16 +17,16 @@ def register(ctx: AuroraContext) -> None:
ctx.register( ctx.register(
"nostd/action/image-properties", "nostd/action/image-properties",
("nostd/mimetype/image-jpeg", "std/status/dialog-infomation"), ("nostd/mimetype/image-jpeg", "std/status/dialog-infomation"),
_build_image_properties_icon, build_image_properties_icon,
) )
ctx.register( ctx.register(
"nostd/action/image-zoom-original", "nostd/action/image-zoom-original",
("nostd/mimetype/image-jpeg", "component/triangles"), ("nostd/mimetype/image-jpeg", "component/triangles"),
_build_image_zoom_original_icon, build_image_zoom_original_icon,
) )
def _build_image_properties_icon(env: AuroraEnvironment) -> None: def build_image_properties_icon(env: AuroraEnvironment) -> None:
art = env.load_temporary_artifact("image-jpeg.png") art = env.load_temporary_artifact("image-jpeg.png")
info_mark = env.load_temporary_artifact("dialog-infomation.png") info_mark = env.load_temporary_artifact("dialog-infomation.png")
@@ -42,27 +45,29 @@ def _build_image_properties_icon(env: AuroraEnvironment) -> None:
env.save_fd_artifact(art, FdContext.Actions, "image-properties") env.save_fd_artifact(art, FdContext.Actions, "image-properties")
def _build_image_zoom_original_icon(env: AuroraEnvironment) -> None: def build_image_zoom_original_icon(env: AuroraEnvironment) -> None:
# load triangle assets # load triangle assets
tri_new_size = (200, 200)
tri_left = env.load_temporary_artifact("component", "triangle-left.png").resize( tri_left = env.load_temporary_artifact("component", "triangle-left.png").resize(
(300, 300), PIL.Image.Resampling.LANCZOS tri_new_size, PIL.Image.Resampling.LANCZOS
) )
tri_down = env.load_temporary_artifact("component", "triangle-down.png").resize( tri_down = env.load_temporary_artifact("component", "triangle-down.png").resize(
(300, 300), PIL.Image.Resampling.LANCZOS tri_new_size, PIL.Image.Resampling.LANCZOS
) )
tri_right = env.load_temporary_artifact("component", "triangle-right.png").resize( tri_right = env.load_temporary_artifact("component", "triangle-right.png").resize(
(300, 300), PIL.Image.Resampling.LANCZOS tri_new_size, PIL.Image.Resampling.LANCZOS
) )
tri_up = env.load_temporary_artifact("component", "triangle-up.png").resize( tri_up = env.load_temporary_artifact("component", "triangle-up.png").resize(
(300, 300), PIL.Image.Resampling.LANCZOS tri_new_size, PIL.Image.Resampling.LANCZOS
) )
# load inner image # load inner image
inner = env.load_temporary_artifact("image-jpeg.png") inner = env.load_temporary_artifact("image-jpeg.png")
resized_inner = inner.resize((570, 570), PIL.Image.Resampling.LANCZOS) resized_inner = inner.resize((680, 680), PIL.Image.Resampling.LANCZOS)
# composite this icon # composite this icon
icon = env.new_artifact() icon = env.new_artifact()
align_paste( align_paste(
icon, icon,
resized_inner, resized_inner,
@@ -71,28 +76,51 @@ def _build_image_zoom_original_icon(env: AuroraEnvironment) -> None:
resized_inner, HorizontalAnchor.Center, VerticalAnchor.Center resized_inner, HorizontalAnchor.Center, VerticalAnchor.Center
), ),
) )
tri_rect = Rectangle.from_margin_rect(VART_HW, VART_HW, 100, 0, 100, 0)
align_alpha_composite( align_alpha_composite(
icon, icon,
tri_left, tri_left,
art_anchor_to_offset(icon, HorizontalAnchor.Left, VerticalAnchor.Center), 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), art_anchor_to_offset(tri_left, HorizontalAnchor.Left, VerticalAnchor.Center),
) )
align_alpha_composite( align_alpha_composite(
icon, icon,
tri_right, tri_right,
art_anchor_to_offset(icon, HorizontalAnchor.Right, VerticalAnchor.Center), 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), art_anchor_to_offset(tri_right, HorizontalAnchor.Right, VerticalAnchor.Center),
) )
align_alpha_composite( align_alpha_composite(
icon, icon,
tri_up, tri_up,
art_anchor_to_offset(icon, HorizontalAnchor.Center, VerticalAnchor.Top), 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), art_anchor_to_offset(tri_up, HorizontalAnchor.Center, VerticalAnchor.Top),
) )
align_alpha_composite( align_alpha_composite(
icon, icon,
tri_down, tri_down,
art_anchor_to_offset(icon, HorizontalAnchor.Center, VerticalAnchor.Bottom), 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), art_anchor_to_offset(tri_down, HorizontalAnchor.Center, VerticalAnchor.Bottom),
) )
@@ -13,7 +13,9 @@ from ..assemblicon.lowlevel.artproc import (
def register(ctx: AuroraContext) -> None: def register(ctx: AuroraContext) -> None:
ctx.register("component/image-base", (), build_image_base_icon) ctx.register("component/image-base", (), build_image_base_icon)
ctx.register("nostd/mimetype/image-jpeg", ("component/image-base",), build_jpg_icon) ctx.register(
"nostd/mimetype/image-jpeg", ("component/image-base",), build_image_jpeg_icon
)
IMAGE_INNER_RECT = Rectangle(Point(20 * 4, 52 * 4), Point(236 * 4, 204 * 4)) IMAGE_INNER_RECT = Rectangle(Point(20 * 4, 52 * 4), Point(236 * 4, 204 * 4))
@@ -26,7 +28,7 @@ def build_image_base_icon(env: AuroraEnvironment) -> None:
) )
def build_jpg_icon(env: AuroraEnvironment) -> None: def build_image_jpeg_icon(env: AuroraEnvironment) -> None:
jpg_image = env.load_temporary_artifact("component", "image-base.png") jpg_image = env.load_temporary_artifact("component", "image-base.png")
jpg_image_inner = env.load_input_bitmap_artifact( jpg_image_inner = env.load_input_bitmap_artifact(
@@ -10,11 +10,6 @@ def register(ctx: AuroraContext) -> None:
ctx.register("std/action/object-flip-*", (), build_object_flip_icons) ctx.register("std/action/object-flip-*", (), build_object_flip_icons)
ctx.register("std/action/object-rotate-*", (), build_object_rotate_icons) ctx.register("std/action/object-rotate-*", (), build_object_rotate_icons)
ctx.register(
"component/triangles",
("component/generic-background",),
build_zoom_triangle_icons,
)
ctx.register( ctx.register(
"std/action/zoom-[original|fit-best]", "std/action/zoom-[original|fit-best]",
("component/triangles",), ("component/triangles",),
@@ -67,34 +62,6 @@ def build_object_rotate_icons(env: AuroraEnvironment) -> None:
env.save_fd_artifact(art, FdContext.Actions, "object-rotate-right") env.save_fd_artifact(art, FdContext.Actions, "object-rotate-right")
def build_zoom_triangle_icons(env: AuroraEnvironment) -> None:
# load triangle and background assets
tri = env.render_svg_then_load(env.input_artifact("component", "triangle.svg"))
bg = env.load_temporary_artifact("component", "generic-background.png")
# create 4 triangle icons for following building
tri_left = env.new_artifact()
tri_left.paste(bg, (0, 0), tri)
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
tri_down = env.new_artifact()
tri_down.paste(bg, (0, 0), tri)
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
tri_right = env.new_artifact()
tri_right.paste(bg, (0, 0), tri)
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
tri_up = env.new_artifact()
tri_up.paste(bg, (0, 0), tri)
# save them for reuse
env.save_temporary_artifact(tri_left, "component", "triangle-left.png")
env.save_temporary_artifact(tri_down, "component", "triangle-down.png")
env.save_temporary_artifact(tri_right, "component", "triangle-right.png")
env.save_temporary_artifact(tri_up, "component", "triangle-up.png")
def build_zoom_origin_and_fit_best_icons(env: AuroraEnvironment) -> None: def build_zoom_origin_and_fit_best_icons(env: AuroraEnvironment) -> None:
# load triangle assets # load triangle assets
tri_left = env.load_temporary_artifact("component", "triangle-left.png") tri_left = env.load_temporary_artifact("component", "triangle-left.png")
@@ -126,9 +93,9 @@ def build_zoom_fit_best_icon(
tri_right: Artifact, tri_right: Artifact,
tri_up: Artifact, tri_up: Artifact,
) -> None: ) -> None:
# TODO: finihs this in future
pass pass
def build_zoom_in_out_icons(env: AuroraEnvironment) -> None: def build_zoom_in_out_icons(env: AuroraEnvironment) -> None:
# TODO: finihs this in future
pass pass
@@ -4,6 +4,11 @@ from ..types import AuroraContext, AuroraEnvironment
def register(ctx: AuroraContext) -> None: def register(ctx: AuroraContext) -> None:
ctx.register("component/generic-background", (), build_generic_background) ctx.register("component/generic-background", (), build_generic_background)
ctx.register(
"component/triangles",
("component/generic-background",),
build_triangle_icons,
)
def build_generic_background(env: AuroraEnvironment) -> None: def build_generic_background(env: AuroraEnvironment) -> None:
@@ -11,3 +16,31 @@ def build_generic_background(env: AuroraEnvironment) -> None:
env.input_artifact("component", "generic-background.svg"), env.input_artifact("component", "generic-background.svg"),
env.temporary_artifact("component", "generic-background.png"), env.temporary_artifact("component", "generic-background.png"),
) )
def build_triangle_icons(env: AuroraEnvironment) -> None:
# load triangle and background assets
tri = env.render_svg_then_load(env.input_artifact("component", "triangle.svg"))
bg = env.load_temporary_artifact("component", "generic-background.png")
# create 4 triangle icons for following building
tri_left = env.new_artifact()
tri_left.paste(bg, (0, 0), tri)
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
tri_down = env.new_artifact()
tri_down.paste(bg, (0, 0), tri)
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
tri_right = env.new_artifact()
tri_right.paste(bg, (0, 0), tri)
tri = tri.transpose(PIL.Image.Transpose.ROTATE_90)
tri_up = env.new_artifact()
tri_up.paste(bg, (0, 0), tri)
# save them for reuse
env.save_temporary_artifact(tri_left, "component", "triangle-left.png")
env.save_temporary_artifact(tri_down, "component", "triangle-down.png")
env.save_temporary_artifact(tri_right, "component", "triangle-right.png")
env.save_temporary_artifact(tri_up, "component", "triangle-up.png")