Refine UI layout and theme behavior

Generalize color selection, reorganize GUI, add presets, dynamic slider adjustments, config defaults, multiple UI updates etc
This commit is contained in:
lm
2025-10-15 20:18:21 +02:00
parent 02255f5dee
commit f9e8d01a70
8 changed files with 401 additions and 76 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ except ModuleNotFoundError: # pragma: no cover - fallback for <3.11
if "tomllib" not in globals():
tomllib = None # type: ignore[assignment]
PREVIEW_MAX_SIZE = (1200, 800)
PREVIEW_MAX_SIZE = (900, 660)
BASE_DIR = Path(__file__).resolve().parents[2]
IMAGES_DIR = BASE_DIR / "images"
+35 -28
View File
@@ -40,9 +40,12 @@ class ImageProcessingMixin:
self.orig_img = image
self.prepare_preview()
self.update_preview()
self.status.config(
text=f"Geladen: {self.image_path.name}{self.orig_img.width}x{self.orig_img.height}"
)
dimensions = f"{self.orig_img.width}x{self.orig_img.height}"
status_text = f"Geladen: {self.image_path.name}{dimensions}"
self.status.config(text=status_text)
self.status_default_text = status_text
if hasattr(self, "filename_label"):
self.filename_label.config(text=f"{self.image_path.name}{dimensions}")
def save_overlay(self) -> None:
if self.orig_img is None:
@@ -57,7 +60,7 @@ class ImageProcessingMixin:
self.exclude_rects,
alpha=int(self.alpha.get()),
scale_from_preview=self.preview_img.size,
is_purple_fn=self.is_purple_pixel,
is_match_fn=self.matches_target_color,
)
merged = Image.alpha_composite(self.orig_img.convert("RGBA"), overlay)
@@ -100,18 +103,18 @@ class ImageProcessingMixin:
stats = self.compute_stats_preview()
if stats:
p_all, t_all = stats["all"]
p_keep, t_keep = stats["keep"]
p_ex, t_ex = stats["excl"]
r_with = (p_keep / t_keep * 100) if t_keep else 0.0
r_no = (p_all / t_all * 100) if t_all else 0.0
excl_share = (t_ex / t_all * 100) if t_all else 0.0
excl_purp = (p_ex / t_ex * 100) if t_ex else 0.0
matches_all, total_all = stats["all"]
matches_keep, total_keep = stats["keep"]
matches_ex, total_ex = stats["excl"]
r_with = (matches_keep / total_keep * 100) if total_keep else 0.0
r_no = (matches_all / total_all * 100) if total_all else 0.0
excl_share = (total_ex / total_all * 100) if total_all else 0.0
excl_match = (matches_ex / total_ex * 100) if total_ex else 0.0
self.ratio_label.config(
text=(
f"Purple (mit Excludes): {r_with:.2f}% | "
f"Purple (ohne Excludes): {r_no:.2f}% | "
f"Excluded: {excl_share:.2f}% vom Bild, davon {excl_purp:.2f}% purple"
f"Treffer (mit Excludes): {r_with:.2f}% | "
f"Treffer (ohne Excludes): {r_no:.2f}% | "
f"Excluded: {excl_share:.2f}% vom Bild, davon {excl_match:.2f}% Treffer"
)
)
@@ -135,7 +138,7 @@ class ImageProcessingMixin:
r, g, b, a = pixels[x, y]
if a == 0:
continue
if self.is_purple_pixel(r, g, b):
if self.matches_target_color(r, g, b):
draw.point((x, y), fill=(255, 0, 0, alpha))
merged = Image.alpha_composite(base, overlay)
for (x0, y0, x1, y1) in self.exclude_rects:
@@ -147,9 +150,9 @@ class ImageProcessingMixin:
return None
px = self.preview_img.convert("RGBA").load()
width, height = self.preview_img.size
purple_all = total_all = 0
purple_keep = total_keep = 0
purple_excl = total_excl = 0
matches_all = total_all = 0
matches_keep = total_keep = 0
matches_excl = total_excl = 0
for y in range(height):
for x in range(width):
r, g, b, a = px[x, y]
@@ -157,19 +160,23 @@ class ImageProcessingMixin:
continue
is_excluded = self._is_excluded(x, y)
total_all += 1
if self.is_purple_pixel(r, g, b):
purple_all += 1
if self.matches_target_color(r, g, b):
matches_all += 1
if not is_excluded:
total_keep += 1
if self.is_purple_pixel(r, g, b):
purple_keep += 1
if self.matches_target_color(r, g, b):
matches_keep += 1
else:
total_excl += 1
if self.is_purple_pixel(r, g, b):
purple_excl += 1
return {"all": (purple_all, total_all), "keep": (purple_keep, total_keep), "excl": (purple_excl, total_excl)}
if self.matches_target_color(r, g, b):
matches_excl += 1
return {
"all": (matches_all, total_all),
"keep": (matches_keep, total_keep),
"excl": (matches_excl, total_excl),
}
def is_purple_pixel(self, r, g, b) -> bool:
def matches_target_color(self, r, g, b) -> bool:
h, s, v = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)
hue = h * 360.0
hmin = float(self.hue_min.get())
@@ -209,7 +216,7 @@ class ImageProcessingMixin:
*,
alpha: int,
scale_from_preview: Tuple[int, int],
is_purple_fn,
is_match_fn,
) -> Image.Image:
overlay = Image.new("RGBA", image.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(overlay)
@@ -223,7 +230,7 @@ class ImageProcessingMixin:
r, g, b, a = pixels[x, y]
if a == 0:
continue
if is_purple_fn(r, g, b):
if is_match_fn(r, g, b):
draw.point((x, y), fill=(255, 0, 0, alpha))
return overlay
+3
View File
@@ -12,6 +12,9 @@ class ResetMixin:
self.val_max.set(self.DEFAULTS["val_max"])
self.alpha.set(self.DEFAULTS["alpha"])
self.update_preview()
default_text = getattr(self, "status_default_text", "Standardwerte aktiv.")
if hasattr(self, "status"):
self.status.config(text=default_text)
__all__ = ["ResetMixin"]